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
Proc
creado porProc.new
oproc
. - Un lambda es un
Proc
creado porlambda
(oproc
en Ruby 1.8).
Ruby tiene tres palabras clave que regresan de algo:
-
return
termina el método o lambda en que se encuentra. -
next
termina el bloque, proc o lambda en el que se encuentra. -
break
termina 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"