2010-04-23 14 views
36

Widziałem to kilka razy, ale nie wiem, jak z nich korzystać. Kilof mówi, że są to specjalne skróty, ale nie udało mi się znaleźć opisu składniowego.Co to są: + i &: + w Ruby?

Widziałem ich w takich kontekstach:

[1,2,3].inject(:+) 

obliczyć sumę na przykład.

+1

Fyi Twój przykład jest źle, powinien przeczytać '[1,2,3] .inject (&: +)' –

+3

I podwójne zaznaczone, [1,2,3] .inject (: +) zdecydowanie działa. Czemu? – Valentin

+0

To musi być cecha metody "wstrzyknąć". 'inject (: +)' nie jest Symbolem # to_proc, ': +' nie ma specjalnego znaczenia w języku ruby ​​- to tylko symbol. –

Odpowiedz

61

Zacznijmy od łatwiejszego przykładu. że mamy tablicę ciągów chcemy mieć w czapkach:

['foo', 'bar', 'blah'].map { |e| e.upcase } 
# => ['FOO', 'BAR', 'BLAH'] 

Ponadto, można tworzyć tak zwane obiekty proc (closures):

block = proc { |e| e.upcase } 
block.call("foo") # => "FOO" 

można przekazać taką proc Do metoda ze składnią &:

block = proc { |e| e.upcase } 
['foo', 'bar', 'blah'].map(&block) 
# => ['FOO', 'BAR', 'BLAH'] 

Co to jest wezwanie to_proc na bloku, a następnie wywołuje, że dla każdego bloku:

some_object = Object.new 
def some_object.to_proc 
    proc { |e| e.upcase } 
end 

['foo', 'bar', 'blah'].map(&some_object) 
# => ['FOO', 'BAR', 'BLAH'] 

Teraz Rails najpierw dodano metodę to_proc do symbolu, który później został dodany do biblioteki rdzenia Ruby

:whatever.to_proC# => proc { |e| e.whatever } 

Dlatego można to zrobić:

['foo', 'bar', 'blah'].map(&:upcase) 
# => ['FOO', 'BAR', 'BLAH'] 

także Symbol # to_proc jest jeszcze bardziej inteligentny, ponieważ faktycznie wykonuje następujące czynności:

:whatever.to_proC# => proc { |obj, *args| obj.send(:whatever, *args) } 

Oznacza to, że

[1, 2, 3].inject(&:+) 

równa

[1, 2, 3].inject { |a, b| a + b } 
+5

'inject' również obsługuje' [1,2,3] .inject (: +) '(zauważ, że nie potrzebujesz &) – horseyguy

+0

w takim przypadku sprawdzi, czy obiekt jest przekazywany do niego na wywołanie to_proc. def wstrzyknąć (obj, i blok) blok || = obj.to_proc # ... końcowy –

+5

To nie na ruby ​​definicję inject. inject nie wywołuje to_proc, używa on rb_funcall z podanym symbolem jako nazwą metody. Zobacz inject_op_i w enum.c. – sepp2k