texto que etiquetas elemento ejemplos ejemplo code clasificadas ruby proc

ruby - etiquetas - que es un elemento en html



Propósito de &(ampersand) en Ruby para procs y métodos de llamada (4)

Me he dado cuenta de que muchos ejemplos relacionados con Ruby Procs tienen el siguiente y el símbolo.

# Ruby Example shout = Proc.new { puts ''Yolo!'' } def shout_n_times(n, &callback) n.times do callback.call end end shout_n_times(3, &shout) # prints ''Yolo!'' 3 times

Mi pregunta es ¿cuál es el propósito funcional detrás del símbolo &? Parece que si escribí el mismo código exacto sin &, funciona como se esperaba:

# Same code as previous without & shout = Proc.new { puts ''Yolo!'' } def shout_n_times(n, callback) n.times do callback.call end end shout_n_times(3, shout) # prints ''Yolo!'' 3 times


Bueno, cuando tienes un bloque , si aplicas & antes del bloque, se convierte en objeto Proc y viceversa.

_unary &_ : tiene algo que ver con convertir cosas desde y hacia bloques. Si no le quita nada más a esto, recuerde que cuando ve un "&" único en Ruby, está pensando en hacer algo en un bloque o en hacer un bloque en algo.

En su primer ejemplo, en esta línea shout_n_times(3, &shout) de shout_n_times(3, &shout) , está convirtiendo el objeto Proc que hace referencia la variable shoot en un block . y luego en la lista de parámetros del método, lo está convirtiendo de nuevo a un objeto Proc .

En su segundo ejemplo funciona, porque está pasando directamente un objeto Proc como un argumento de método y luego está llamando a #call en él.


Como complemento, me recuerdo & como un signo de conversión entre block y Proc .

Para convertir un block a Proc

def foo(&p) puts p.class end foo {} # => Proc

Para convertir un Proc en un block

def bar yield "hello" end p = Proc.new {|a| puts a } bar &p # => hello


La diferencia es que en tu primer ejemplo:

# Ruby Example shout = Proc.new { puts ''Yolo!'' } def shout_n_times(n, &callback) n.times do callback.call end end shout_n_times(3, &shout)

... la sintaxis de la llamada a su método le permite reescribir la definición del método de la siguiente manera:

shout = Proc.new { puts ''Yolo!'' } def shout_n_times(n) n.times do yield end end shout_n_times(3, &shout) --output:-- Yolo! Yolo! Yolo!

Estas dos afirmaciones:

shout = Proc.new { puts ''Yolo!'' } ... shout_n_times(3, &shout)

... son equivalentes a:

shout_n_times(3) do puts ''Yolo!'' end

Y escribir el rendimiento () dentro de la definición del método de shout_n_times () llama al bloque que se especifica después de la llamada al método:

method call +--start of block specified after the method call | | V V shout_n_times(3) do puts ''Yolo!'' end ^ | +--end of block

Verá, un bloque es como un método, y un bloque se pasa como un argumento invisible en la llamada al método después de lo cual se escribe el bloque. Y dentro de la definición del método, quien haya escrito la definición del método puede ejecutar el bloque con el rendimiento (). Los bloques de Ruby no son más que una sintaxis especial que le permite pasar un método como argumento a otro método.


Este artículo proporciona una buena visión general de las diferencias.

Para resumir el artículo, Ruby permite bloques implícitos y explícitos. Además, Ruby tiene block, proc y lambda.

Cuando usted llama

def foo(block) end

block es solo un argumento simple del método. Se hace referencia al argumento en el block variables, y la forma en que interactúa con él depende del tipo de objeto que pase.

def foo(one, block, two) p one p block.call p two end foo(1, 2, 3) 1 NoMethodError: undefined method `call'' for 2:Fixnum from (irb):3:in `foo'' from (irb):6 from /Users/weppos/.rvm/rubies/ruby-2.1.5/bin/irb:11:in `<main>'' foo(1, Proc.new { 1 + 1 }, 3) 1 2 3

Pero cuando utiliza el símbolo & en la definición del método, el bloque adquiere un significado diferente. Estás definiendo explícitamente un método para aceptar un bloque. Y se aplicarán otras reglas (como no más de un bloque por método).

def foo(one, two, &block) p one p block.call p two end

En primer lugar, al ser un bloque, la firma del método ahora acepta "dos parámetros y un bloque", no "tres parámetros".

foo(1, 2, Proc.new { "from the proc" }) ArgumentError: wrong number of arguments (3 for 2) from (irb):7:in `foo'' from (irb):12 from /Users/weppos/.rvm/rubies/ruby-2.1.5/bin/irb:11:in `<main>''

Eso significa que tienes que forzar que el tercer argumento sea un bloque que pasa el parámetro con el signo.

foo(1, 2, &Proc.new { "from the proc" }) 1 "from the proc" 2

Sin embargo, esta es una sintaxis muy poco común. En Ruby, los métodos con bloques generalmente se llaman usando {}

foo(1, 2) { "from the block" } 1 "from the block" 2

o do end

foo(1, 2) do "from the block" end 1 "from the block" 2

Volvamos a la definición del método. Anteriormente mencioné que el siguiente código es una declaración de bloque explícita .

def foo(one, two, &block) block.call end

Los métodos pueden aceptar implícitamente un bloque. Los bloques implícitos se llaman con yield .

def foo(one, two) p yield end foo(1, 2) { "from the block" }

¿Puedes comprobar que se pasa el bloque usando block_given?

def foo(one, two) if block_given? p yield else p "No block given" end end foo(1, 2) { "from the block" } => "from the block" foo(1, 2) => "No block given"

Estas características relacionadas con el bloque no estarían disponibles si declara el "bloque" como un argumento simple (por lo tanto, sin el símbolo comercial), porque solo sería un argumento de método anónimo.