2013-02-14 10 views
31

Uczę się szyn i podążam za this thread. Utknąłem w metodzie to_proc. Uważam symbole za alternatywę dla łańcuchów (są one podobne do łańcuchów, ale tańsze pod względem pamięci). Jeśli jest coś jeszcze, czego mi brakuje do symboli, proszę powiedz mi. Proszę wyjaśnić w prosty sposób, co oznacza to_proc i do czego służy.Co oznacza metoda to_proc?

Odpowiedz

77

Niektóre metody wziąć blok, a ten wzór często pojawia się na bloku:

{|x| x.foo} 

i ludzie chcieliby, aby napisać, że w bardziej zwięzły sposób. W tym celu stosuje się w połączeniu symbol, metodę domyślnego rzucania klas i operatora &. Jeśli umieścisz & przed instancją Proc w pozycji argumentu, zostanie to zinterpretowane jako blok. Jeśli połączysz coś innego niż instancja Proc z &, niejawne rzutowanie klas spróbuje przekonwertować to na instancję Proc, używając metody zdefiniowanej dla tego obiektu, o ile istnieje. W przypadku instancji Symbol, to_proc działa w ten sposób:

:foo.to_proC# => ->x{x.foo} 

Na przykład, załóżmy, że piszesz tak:

bar(&:foo) 

Operator & łączy się z :foo, który nie jest instancją Proc , więc niejawna klasa rzuca się do niego, co daje Symbol#to_proc, co daje ->x{x.foo}. & stosuje teraz do tego i jest interpretowane jako blok, co daje:

bar{|x| x.foo} 
+3

dzięki za wyjaśnienie +1 :) – swapnesh

+0

Plus, zgodnie z tym , jest 20 razy szybciej podczas pracy. –

+0

Rozumiem, że '& proc' daje blok,' & x' powoduje, że x staje się procem, a całość daje blok. Rozumiem również, że Symbol ma metodę to_proc. Jednak w części, której nie rozumiem i czuję, że ta odpowiedź nie istnieje, to w jaki sposób symbol i metody są ze sobą powiązane. mam na myśli to, że nie wszystkie metody są dostępne również pod nazwami symboli –

39

Najłatwiej wyjaśnić to na przykładach.

(1..3).collect(&:to_s) #=> ["1", "2", "3"] 

jest taka sama jak:

(1..3).collect {|num| num.to_s} #=> ["1", "2", "3"] 

i

[1,2,3].collect(&:succ) #=> [2, 3, 4] 

jest taka sama jak:

[1,2,3].collect {|num| num.succ} #=> [2, 3, 4] 

to_proc zwraca obiekt Proc który reaguje na danej metody według symbolu. Tak więc w trzecim przypadku tablica [1,2,3] wywołuje metodę collect i. succ jest metodą zdefiniowaną przez klasę Array. Zatem ten parametr jest krótkim sposobem na powiedzenie zebrania każdego elementu w tablicy i zwrócenia jego następcy, a następnie utworzenia nowej tablicy, która daje [2,3,4]. Symbol: succ jest konwertowany na obiekt Proc, więc wywołuje metodę succ Array.

+3

@Doszon +1 dla przykładów :) – swapnesh

7

Dla mnie najwyraźniejszym wyjaśnieniem jest prosta implementacja tego.Oto, co to może wyglądać jakbym reimplementing symbol # to_proc:

class Symbol # reopen Symbol class to reimplement to_proc method 
    def to_proc 
    ->(object) { object.send(self) } 
    end 
end 

my_lambda = :to_s.to_proc 

puts my_lambda.(1) # prints '1'; .() does the same thing as .call() 
puts my_lambda.(1).class # prints 'String' 

puts [4,5,6].map(&:to_s) # prints "4\n5\n6\n" 
puts [4,5,6].map(&:to_s).first.class # prints 'String' 
+1

To! A propos, czy nie powinno to być "my_to_proc" w metodzie, w której próbujesz patchować małpy w klasie "Symbol"? –

+0

@AgungSetiawan Dobry połów! Zamiast tego zmieniłem nazwę połączenia tak, aby wywoływał on_proc zamiast my_to_proc. –

1

Dla nikogo jeszcze trochę zakłopotany, działa następujący kod może zrobić rzeczy trochę jaśniej:

class Symbol 
    def to_proc 
    proc do |obj| 
     puts "Symbol proc: #{obj}.send(:#{self})" 
     obj.send(self) 
    end 
    end 
end 

class Array 
    def map(&block) 
    copy = self.class.new 
    self.each do |index| 
     puts "Array.map: copy << block.call(#{index})" 
     copy << block.call(index) 
    end 
    copy 
    end 
end 

remapped_array = [0, 1, 2].map &:to_s 
puts "remapped array: #{remapped_array.inspect}" 

te nie są Rzeczywiste implementacje Symbol.to_proc lub Array.map są tylko uproszczonymi wersjami, których używam do demonstrowania, jak działają map &:to_s i podobne wywołania.