tutorial - ruby wikipedia
¿Cuál es la diferencia entre un proc y un lambda en Ruby? (5)
¿Y cuándo usarías uno en lugar de otro?
En general, las lambdas son más intuitivas que los procs porque son más similares a los métodos. Son bastante estrictos con respecto a la arity, y simplemente salen cuando llamas a return. Por este motivo, muchos Rubyistas usan lambdas como primera opción, a menos que necesiten las características específicas de los procesos.
Procs: Objetos de la clase Proc
. Al igual que los bloques, se evalúan en el ámbito en el que están definidos. Lambdas: también objetos de clase Proc
pero sutilmente diferentes de los procesos regulares. Son cierres como bloques y procesos, y como tales se evalúan en el ámbito en el que están definidos.
Creando Proc
a = Proc.new { |x| x 2 }
Creando lambda
b = lambda { |x| x 2
b = lambda { |x| x 2
}
Es algo sutil. Ambos son métodos que crean cierres y ambos devuelven objetos Proc. También hay una tercera vía: Proc.new
. La diferencia está en cómo se comportan, y los detalles dependen de si estás usando Ruby 1.8 o 1.9 (de hecho, hay otra forma de crearlos en Ruby 1.9). En el caso general, la diferencia no es algo de lo que deba preocuparse. Solo cuando te preocupa el rigor, hace la diferencia. Cuándo usar lambda, cuándo usar Proc.new? cubre las diferencias bastante bien.
La diferencia real entre procs y lambdas tiene mucho que ver con las palabras clave de flujo de control. Estoy hablando de return
, raise
, break
, redo
, retry
, etc. - esas palabras de control. Digamos que tienes una declaración de devolución en un proceso. Cuando llame a su proc, no solo lo expulsará de él, sino que también lo devolverá desde el método adjunto, por ejemplo:
def my_method
puts "before proc"
my_proc = Proc.new do
puts "inside proc"
return
end
my_proc.call
puts "after proc"
end
my_method
shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
El final puts
en el método, nunca se ejecutó, ya que cuando llamamos a nuestro proceso, el return
dentro de él nos expulsó del método. Sin embargo, si convertimos nuestro proceso a un lambda, obtenemos lo siguiente:
def my_method
puts "before proc"
my_proc = lambda do
puts "inside proc"
return
end
my_proc.call
puts "after proc"
end
my_method
shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
after proc
El retorno dentro de la lambda solo nos arroja fuera de la lambda y el método adjunto continúa ejecutándose. La forma en que las palabras clave de control de flujo se tratan dentro de los procesos y lambdas es la principal diferencia entre ellas
Una diferencia es en la forma en que manejan los argumentos. Crear un proceso usando proc {}
y Proc.new {}
es equivalente. Sin embargo, el uso de lambda {}
le proporciona un proceso que verifica la cantidad de argumentos que se le pasan. De ri Kernel#lambda
:
Equivalente a Proc.new , excepto los objetos Proc resultantes, verifique el número de parámetros pasados cuando se los llama.
Un ejemplo:
p = Proc.new {|a, b| puts a**2+b**2 } # => #<Proc:0x3c7d28@(irb):1>
p.call 1, 2 # => 5
p.call 1 # => NoMethodError: undefined method `**'' for nil:NilClass
p.call 1, 2, 3 # => 5
l = lambda {|a, b| puts a**2+b**2 } # => #<Proc:0x15016c@(irb):5 (lambda)>
l.call 1, 2 # => 5
l.call 1 # => ArgumentError: wrong number of arguments (1 for 2)
l.call 1, 2, 3 # => ArgumentError: wrong number of arguments (3 for 2)
Además, como señala Ken, al usar return
dentro de una lambda se devuelve el valor de esa lambda, pero al usar return
en un proc regresa del bloque adjunto.
lambda { return :foo }.call # => :foo
return # => LocalJumpError: unexpected return
Proc.new { return :foo }.call # => LocalJumpError: unexpected return
Por lo tanto, para la mayoría de los usos rápidos son los mismos, pero si desea una verificación de argumento estricta automática (que a veces también puede ayudar con la depuración), o si necesita usar la declaración return para devolver el valor del proceso, use lambda
.
las diferencias entre proc y lambda es que proc es solo una copia de código con argumentos reemplazados a su vez, mientras que lambda es una función como en otros lenguajes. (comportamiento de devolución, verificaciones de argumentos)