yield
ing un bloque
lambda?
determina si un objeto Proc es una lambda o un proc
return
nos saca del método en el que estamos, no del bloque en el que estamos:
def test puts "entering method" 1.times { puts "entering block"; return } # Makes test method return puts "exiting method" # This line is never executed end test
return
nos saca del método en el que estamos, no del proc en el que estamos:
def test puts "entering method" p = Proc.new { puts "entering proc"; return } p.call # Invoking the proc makes method return puts "exiting method" # This line is never executed end test
return
dentro de un proc puede sorprender un poco:
def procBuilder(message) # Create and return a proc Proc.new { puts message; return } # return returns from procBuilder end def test puts "entering method" p = procBuilder("entering proc") p.call # Prints "entering proc" and raises LocalJumpError! puts "exiting method" # This line is never executed end testCuando lo ejecutamos obtenemos:
$ ruby procjump.rb entering method entering proc procjump.rb:2:in `block in procBuilder': unexpected return (LocalJumpError)Al convertir el bloque en un objeto podemos pasar el bloque y utilizarlo fuera de su contexto.
return
dentro de una lambda
retorna desde la lambda no desde el método que contiene a la lambda
def test puts "entering method" p = lambda { puts "entering lambda"; return } p.call # Invoking the lambda does not make the method return puts "exiting method" # This line *is* executed now end test
return
en una lambda
caiga fuera de contexto
def lambdaBuilder(message) # Create and return a lambda lambda { puts message; return } # return returns from the lambda end def test puts "entering method" l = lambdaBuilder("entering lambda") l.call # Prints "entering lambda" puts "exiting method" # This line is executed end test
break
transfiere el control a la
primera sentencia que sigue al bucle:
while(line = gets.chop) # A loop starts here break if line == "quit" # If this break statement is executed... puts eval(line) end puts "Good bye" # ...then control is transferred here
break
transfiere el control fuera
del bloque, fuera del iterador hasta la primera expresión que sigue
a la invocación del iterador:
f.each do |line| # Iterate over the lines in file f break if line == "quit\n" # If this break statement is executed... puts eval(line) end puts "Good bye" # ...then control is transferred here
Proc.new
, el iterador desde el que se sale es
Proc.new
. Eso significa que si el proc con el break
es llamado
fuera de contexto obtendremos un error:
$ cat procbreak.rb 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 $ ruby procbreak.rb entering test method entering proc procbreak.rb:3:in `block in test': break from proc-closure (LocalJumpError)`
$ cat procbreakwithampersand.rb 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 testla cosa funciona bien porque el proc está en contexto:
$ ruby procbreakwithampersand.rb entering iterator entering proc
break
funciona igual que dentro de un método:
$ cat lambdabreak.rb def test puts "entering test method" lambda = lambda { puts "entering lambda"; break; puts "exiting lambda" } lambda.call puts "exiting test method" end testde hecho el
break
actúa como un return
y nos saca de la lambda:
$ ruby lambdabreak.rb entering test method entering lambda exiting test method
next
al nivel mas alto produce el mismo efecto en un bloque,
proc o lambda: hace que se retorne del yield
o del call
que
invoca el bloque, proc o lambda
next
va seguido de una expresión es usada como valor de retorno
del bloque, proc o lambda
redo
transfiere el control al comienzo del bloque o lambda
retry
no esta permitido ni en procs ni en lambdas
raise
rescue
yield
son asignados a los parámetros
de un bloque siguiendo reglas que son mas próximas a las reglas de asignación
de variables que a las reglas de invocación de métodos
yield k,v |
do |key, value| ... end |
funciona como
key, value = k, v
def two; yield 1,2; end # An iterator that yields two values two {|x| p x } # Ruby 1.8: warns and prints [1,2], two {|x| p x } # Ruby 1.9: prints 1, no warning two {|*x| p x } # Either version: prints [1,2]; no warning two {|x,| p x } # Either version: prints 1; no warning
def five; yield 1,2,3,4,5; end # Yield 5 values five do |head, *body, tail| # Extra values go into body array print head, body, tail # Prints "1[2,3,4]5" end
yield
permite bare hashes:
def hashiter; yield :a=>1, :b=>2; end # Note no curly braces hashiter {|hash| puts hash[:a] } # Prints 1
&
para indicar que será utilizado para recibir el bloque asociado con la invocación
del bloque:
# This Proc expects a block printer = lambda {|&b| puts b.call } # Print value returned by b printer.call { "hi" } # Pass a block to the block!
ruby-1.9.2-head :001 > [1,2,3].each { |x,y=2| puts x*y } 2 4 6 => [1, 2, 3]o también:
ruby-1.9.2-head :007 > [1,2,3].each &->(x, y=2) { puts x*y } 2 4 6 => [1, 2, 3]
yield
usa semántica yield mientras que la invocación de un método
usa semántica de invocación
p = Proc.new {|x,y| print x,y } p.call(1) # x,y=1: nil used for missing rvalue: Prints 1nil p.call(1,2) # x,y=1,2: 2 lvalues, 2 rvalues: Prints 12 p.call(1,2,3) # x,y=1,2,3: extra rvalue discarded: Prints 12 p.call([1,2]) # x,y=[1,2]: array automatically unpacked: Prints 12
l = lambda {|x,y| print x,y } l.call(1,2) # This works l.call(1) # Wrong number of arguments l.call(1,2,3) # Wrong number of arguments l.call([1,2]) # Wrong number of arguments l.call(*[1,2]) # Works: explicit splat to unpack the array
Casiano Rodriguez León 2015-01-07