2010-04-23 22 views
36

He visto esto varias veces, pero no sé cómo usarlas. El pico dice que estos son atajos especiales, pero no pude encontrar la descripción sintáctica.¿Qué son: + y &: + en Ruby?

Los he visto en estos contextos:

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

para calcular la suma, por ejemplo.

+1

FYI tu ejemplo es incorrecto, debe decir '[1,2,3] .inject (y +)' –

+3

me doble registrado, el [1,2,3] .inject (: +) definitivamente funciona. ¿Por qué? – Valentin

+0

Debe ser una característica del método 'inject', entonces. 'inject (: +)' no es Symbol # to_proc, ': +' no tiene ningún significado especial en el lenguaje ruby, es solo un símbolo. –

Respuesta

61

Comencemos con un ejemplo más fácil. Digamos que tenemos una matriz de cadenas que queremos tener en mayúsculas:

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

Además, se pueden crear los llamados objetos Proc (vedas):

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

puede pasar un proc este tipo a una método con la sintaxis &:

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

lo que esto hace, es to_proc llamada en bloque y luego llama a que por cada bloque:

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

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

Ahora, rieles añade en primer lugar el método to_proc en símbolo, que más tarde se ha agregado a la biblioteca central de rubí:

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

Por lo tanto usted puede hacer esto:

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

Además, Símbolo # to_proc es aún más inteligente, ya que en realidad hace lo siguiente:

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

Esto significa que

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

es igual a

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

'inject' también admite' [1,2,3] .inject (: +) '(tenga en cuenta que no necesita el &) – horseyguy

+0

en ese caso, comprobará si un objeto recibe una llamada to_proc en sí mismo. def inyectar (obj, y bloque) bloque || = obj.to_proc # ... final –

+5

eso no es de Ruby definición de inyección. inject no llama a to_proc, usa rb_funcall con el símbolo dado como el nombre del método. Ver inject_op_i en enum.c. – sepp2k

Cuestiones relacionadas