¿Por qué la declaración de descanso en Ruby se comporta de manera diferente cuando se usa Proc.New v. El signo de ampers y?
-
29-10-2019 - |
Pregunta
La declaración de descanso para bloques (según El lenguaje de programación de Ruby) se define de la siguiente manera:
Hace que el bloque regrese a su iterador y al iterador para volver al método que lo invocó.
Por lo tanto, cuando se ejecuta el siguiente código, resulta en un localJumperror.
def test
puts "entering test method"
proc = Proc.new { puts "entering proc"; break }
proc.call # LocalJumpError: iterator has already returned
puts "exiting test method"
end
test
Mientras que el siguiente código no es Lanza un local Jumperror. ¿Qué tiene de especial el signo de Amperands? ¿No usa implícitamente el signo de Ampers y Proc.New?
def iterator(&proc)
puts "entering iterator"
proc.call # invoke the proc
puts "exiting iterator" # Never executed if the proc breaks
end
def test
iterator { puts "entering proc"; break }
end
test
En otras palabras, leí el signo de Amperandand como un medio para encender la llamada de Proc.Nnew. En ese momento el comportamiento debe ser el mismo que el primer fragmento de código.
def iterator (p = Proc.new { puts "entering proc"; break})
...
end
Descargo de responsabilidad: Estoy aprendiendo el idioma (Ruby 1.9.2) y, por lo tanto, apreciaré las referencias y una sinopsis detallada.
Solución
break
Hace el bloque y la llamador del retorno del bloque. En el siguiente código:
proc = Proc.new { break }
La "persona que llama" del bloque que se convierte en un objeto PROC es PROC.NEW. break
Se supone que debe hacer que la persona que llama del bloque regrese, pero Proc.New ya ha regresado.
En este código:
def iterator(&b); b.call; end
iterator { break }
La persona que llama del bloque es iterator
, así que hace iterator
devolver.
Otros consejos
Aquí esta la responder.
Ampersand se usa para convertir un proceso a un bloque y un bloque a un proc.
Cambié el ejemplo para relacionarme con su caso:
def run_my_code(&my_code)
puts 'before proc'
my_code.call
puts 'after proc'
end
run_my_code { puts "passing a block, accepting a proc"; break}
=> before proc
passing a block, accepting a proc
Como puede ver, no llegó al 'después de Proc'
def run_my_code
yield
end
my_proc = Proc.new { puts "passing a proc instead of block"; break}
run_my_code &my_proc
=> passing a proc instead of block
LocalJumpError: break from proc-closure
from (pry):75:in `block in <main>'
En su segundo ejemplo tiene un proceso en resultado, el proceso se rompe de iterator
y vuelve a test
función.
def iterator(&proc)
puts 'entering iterator'
proc.call
puts 'exiting iterator'
end
def test
puts 'before test'
iterator { puts 'entering proc'; break }
puts 'after test'
end
=>before test
entering iterator
entering proc
after test
Tiene que ver con la diferencia entre bloques, procs y lambdas, y sus respectivos ámbitos.
Escribí una publicación al respecto en 2009 que puede encontrar útil: http://www.leonardoborges.com/writings/2009/07/22/procs-lambdas-blocks-whats-tiferference/
Espero que esto ayude.