2015-02-07 10 views
5

Lubię jak w Ruby można przekazać metod jako bloki podobnie jak przy użyciu Symbol#to_proc:Symbol # to_proc metodami niestandardowymi

[1.0, 2.0, 3.0].map(&:to_i) 
#=> [1, 2, 3] 

Mogę również definiować własne lambda times_two i przekazać go jako blok, a także :

times_two = ->(x) {x * 2} 

[1, 2, 3].map(&times_two) 
#=> [2, 4, 6] 

Choć pozornie nie może wprost times_two jako symbol:

[1, 2, 3].map(&:times_two) 
#=> ArgumentError: wrong number of arguments (0 for 1) 

Jednak gdy próbuję zrobić to samo z metody pojawia się błąd:

def times_three(x) 
    x * 3 
end 

[1, 2, 3].map(&times_three) 
#=> ArgumentError: wrong number of arguments (0 for 1) 

[1, 2, 3].map(&:times_three) 
#=> ArgumentError: wrong number of arguments (0 for 1) 

Zgaduję, że nie może tego zrobić, ponieważ times_three jest metodą, a nie Proc.

Jak zdefiniować metody niestandardowe, aby można je było stosować w stylu w pierwszym przykładzie powyżej?

Na przykład, jak mogę to zrobić?

[1, 2, 3].map(&:times_three) 
#=> [3, 6, 9] 

EDIT: oglądałem film pisał poniżej i widocznie można zbliżyć się do Symbol # to_proc stosując metodę method:

def times_three(x) 
    x * 3 
end 

t_three = method(:times_three) 
[1, 2, 3].map(&t_three) 
#=> [3, 6, 9] 

Jednak nie dość Symbol # to_proc:

[1, 2, 3].map(&:t_three) 
#=> NoMethodError: undefined method `t_three' for 1:FixNum 

Odpowiedz

5
class Integer 
    def times_three 
    return self * 3 
    end 
end 

Teraz, ponieważ times_three jest to metoda klasy Integer, można zrobić symbol z PROC ...

[1, 2, 3].map(&:times_three) 

Jeśli chcesz uzyskać dostęp do metody, która nie jest częścią klasy obiektu, ale działa na obiekcie, musisz przekazać obiekt jako argument do metody ...

def times_three(x) 
    x * 3 
end 

[1, 2, 3].map{|i| times_three(i) } 

wymaga użycia obiektu jako odbiornika.

[1, 2, 3].map(&:some_action) 

jest równoważna

[1, 2, 3].map{|i| i.some_action} 
+0

Bardzo dziękuję za to jasne wyjaśnienie, Steve. Skoro już wiem, jak to zrobić, czy dopuszczalne jest praktykowanie małpich klas rdzeniowych za pomocą takich metod, aby wyczyścić skomplikowane lub powtarzające się bloki? – garythegoat

+0

Cóż, tak, pod warunkiem, że intencja jest jasna i jest pewna korzyść, na pewno jest łatka dla małpy. W tym tygodniu miałem aplikację szyn, w której obowiązkowe pola wejściowe miały gwiazdkę w etykietach, np. '' First Name * '' and ''City *'' i firma nagle chciała, aby wszystkie gwiazdki miały czerwony kolor czcionki. Mógłbym napisać metodę pomocniczą, taką jak 'red_asterisk ('First Name *')' ale łatwiej było małpować łatkę klasy String ''First Name *." Red_asterisk', a następnie po prostu zrobić globalne find/replace on '* "więc stało się' * '. red_asterisk' – SteveTurczyn

+0

Steve, jak dobrze wiesz, 'return' nie jest potrzebny. 'self' jest jednak. Zakładam, że 'self' musi być jawne dla takich metod, jak' * ','% ', które są fakturowane za pomocą cukru syntaktycznego. Czy ty lub ktoś inny wie, czy to prawda? –

1

Użytkownik musiałby zdefiniować times_three na Integer lub Numeric.

Symbol do Proc wyjaśnia Peter Cooper: https://www.youtube.com/watch?v=aISNtCAZlMg

+3

Zamiast łączącego losowej odniesienia, należy napisać krótkie wyjaśnienie/skopiować go tutaj i podać link jako źródło swojej anwser. – Smar

+0

Dzięki za wideo. Jednak nie pokazuje, dlaczego musiałbym zdefiniować '' 'times_three''' na' 'Integer''' lub' 'Numeric'''. Pokazuje, w jaki sposób '' 'to_proc''' jest zaimplementowane na klasie, zanim Ruby zaadaptuje Symbol # to_proc, chociaż wideo nie pokazuje, w jaki sposób możesz zdefiniować własne metody w ten sposób. – garythegoat

+1

@garythegoat: Pokazuje, jak implementowane jest 'Symbol # to_proc', mianowicie, że wywołuje metodę na pierwszym argumencie bloku, przekazując inne argumenty bloku jako argumenty wywołania metody. W twoim przypadku pierwszym argumentem bloku jest '1' (w pierwszej iteracji) i nie ma innych argumentów, więc' Symbol # to_proc' wywołuje '1.times_three', ergo,' times_three' musi być zdefiniowany w jednej z klas '1', tj.' Fixnum', 'Integer',' Numeric', 'Object',' Kernel' lub 'BasicObject'. Niestety, [dokument to bzdura] (http://ruby-doc.org/core-2.2.0/Symbol.html#method-i-to_proc), ... –

Powiązane problemy