ruby - ¿Por qué el retorno explícito hace una diferencia en un proceso?
return proc-object (3)
Esta es la semántica para Proc s; No es necesariamente la semántica de todos los bloques. Estoy de acuerdo, esto es un poco confuso. Está ahí para mayor flexibilidad (y quizás en parte porque Ruby no tiene especificaciones, excepto por su implementación).
El comportamiento se define en la implementación de Proc . Lambda comportan de manera diferente, por lo que si desea que su return no salga del método de cierre , use las lambdas . O bien, omita la palabra clave de return de su Proc .
Una investigación profunda de los cierres de Rubys está aquí . Es una exposición fantástica.
Asi que:
def foo
f = Proc.new {
p2 = Proc.new { return "inner proc"};
p2.call
return "proc"
}
f.call
return "foo"
end
def foo2
result = Proc.new{"proc"}.call
"foo2 (proc result is: #{result})"
end
def bar
l = lambda { return "lambda" }
result = l.call
return "bar (lambda result is: #{result})"
end
puts foo
# inner proc
puts foo2
# foo (proc result is: proc)
puts bar
# bar (lambda result is: lambda)
def foo
f = Proc.new { return "return from foo from inside proc" }
f.call # control leaves foo here
return "return from foo"
end
def bar
b = Proc.new { "return from bar from inside proc" }
b.call # control leaves bar here
return "return from bar"
end
puts foo # prints "return from foo from inside proc"
puts bar # prints "return from bar"
Pensé que la palabra clave return era opcional en Ruby y que siempre la está return , ya sea que la solicite o no. Teniendo en cuenta esto, me sorprende que foo y bar tengan una salida diferente determinada por el hecho de que foo contiene un return explícito en Proc f .
¿Alguien sabe por qué este es el caso?
Piénselo de esta manera: Proc.new simplemente crea un bloque de código que forma parte de la función de llamada. proc / lambda crea una función anónima que tiene enlaces especiales. Unos pequeños ejemplos de código ayudarán:
def foo
f = Proc.new { return "return from foo from inside Proc.new" }
f.call # control leaves foo here
return "return from foo"
end
es equivalente a
def foo
begin
return "return from foo from inside begin/end" }
end
return "return from foo"
end
así que está claro que la devolución solo regresará de la función ''foo''
a diferencia de:
def foo
f = proc { return "return from foo from inside proc" }
f.call # control stasy in foo here
return "return from foo"
end
es equivalente a (ignorando los enlaces ya que no se utiliza en este ejemplo):
def unonymous_proc
return "return from foo from inside proc"
end
def foo
unonymous_proc()
return "return from foo"
end
Lo cual es tan claro que no volverá de foo y continuará con la siguiente declaración.
Ruby tiene tres construcciones:
- Un bloque no es un objeto y se crea mediante
{...}odo...end. - Un proc es un objeto
Proccreado porProc.newoproc. - Un lambda es un
Proccreado porlambda(oprocen Ruby 1.8).
Ruby tiene tres palabras clave que regresan de algo:
-
returntermina el método o lambda en que se encuentra. -
nexttermina el bloque, proc o lambda en el que se encuentra. -
breaktermina el método que cedió al bloque o invocó el proc o lambda en el que se encuentra.
En las lambdas, el return comporta como el next , por el motivo que sea. next y break se denominan como están porque se usan más comúnmente con métodos como each , donde la terminación del bloque hará que la iteración se reanude con el siguiente elemento de la colección, y la terminación de each hará que salga del bucle .
return dentro de la definición de foo , regresarás de foo , incluso si está dentro de un bloque o un proc. Para regresar de un bloque, puede usar la next palabra clave en su lugar. def foo
f = Proc.new { next "return from foo from inside proc" }
f.call # control leaves foo here
return "return from foo"
end
puts foo # prints "return from foo"