346 Stimmen

Wann wird Lambda, wann Proc.new verwendet?

In Ruby 1.8 gibt es feine Unterschiede zwischen proc/lambda auf der einen Seite und Proc.new auf der anderen Seite.

  • Worin bestehen diese Unterschiede?
  • Können Sie Hinweise geben, wie man sich für eine der beiden entscheiden kann?
  • In Ruby 1.9 sind proc und lambda unterschiedlich. Was hat es damit auf sich?

11voto

krusty.ar Punkte 3995

Ein guter Weg, um es zu sehen ist, dass Lambdas in ihrem eigenen Bereich ausgeführt werden (als ob es ein Methodenaufruf war), während Procs als Inline mit der aufrufenden Methode ausgeführt werden kann, zumindest ist das ein guter Weg, um zu entscheiden, welche in jedem Fall zu verwenden.

11voto

Evan Moran Punkte 3347

Kurze Antwort: Was zählt, ist, was return tut: lambda kehrt aus sich selbst heraus zurück, und proc kehrt aus sich selbst heraus UND aus der Funktion zurück, die es aufgerufen hat.

Was weniger klar ist, ist, warum Sie beide verwenden wollen. lambda ist das, was wir im Sinne der funktionalen Programmierung von Dingen erwarten. Es handelt sich im Grunde um eine anonyme Methode, bei der der aktuelle Bereich automatisch gebunden ist. Von den beiden ist lambda diejenige, die Sie wahrscheinlich verwenden sollten.

Proc hingegen ist sehr nützlich für die Implementierung der Sprache selbst. Sie können damit zum Beispiel "if"-Anweisungen oder "for"-Schleifen implementieren. Jede Rückgabe, die in der Proc gefunden wird, kehrt aus der Methode zurück, die sie aufgerufen hat, nicht nur aus der "if"-Anweisung. So funktionieren Sprachen, so funktionieren "if"-Anweisungen, also vermute ich, dass Ruby dies im Verborgenen nutzt und es nur offengelegt wurde, weil es mächtig erschien.

Sie benötigen dies nur, wenn Sie neue Sprachkonstrukte wie Schleifen, if-else-Konstruktionen usw. erstellen.

8voto

Verschlüsse in Ruby ist ein guter Überblick darüber, wie Blöcke, Lambdas und Procs in Ruby funktionieren, mit Ruby.

7voto

Dave Rapin Punkte 1483

Ich habe keine Kommentare zur dritten Methode in der Frage, "proc", gefunden, die veraltet ist, aber in 1.8 und 1.9 anders gehandhabt wird.

Hier ein recht ausführliches Beispiel, an dem die Unterschiede zwischen den drei ähnlichen Aufrufen leicht zu erkennen sind:

def meth1
  puts "method start"

  pr = lambda { return }
  pr.call

  puts "method end"  
end

def meth2
  puts "method start"

  pr = Proc.new { return }
  pr.call

  puts "method end"  
end

def meth3
  puts "method start"

  pr = proc { return }
  pr.call

  puts "method end"  
end

puts "Using lambda"
meth1
puts "--------"
puts "using Proc.new"
meth2
puts "--------"
puts "using proc"
meth3

6voto

weakish Punkte 26431

Lambda funktioniert wie erwartet, wie in anderen Sprachen.

Die verkabelte Proc.new ist überraschend und verwirrend.

En return Anweisung in proc created by Proc.new nicht nur die Kontrolle über sich selbst zurück, sondern auch von der sie einschließenden Methode .

def some_method
  myproc = Proc.new {return "End."}
  myproc.call

  # Any code below will not get executed!
  # ...
end

Sie können argumentieren, dass Proc.new fügt Code in die einschließende Methode ein, genau wie block. Aber Proc.new erzeugt ein Objekt, während Block Teil von ein Objekt.

Und es gibt noch einen weiteren Unterschied zwischen lambda und Proc.new das ist ihr Umgang mit (falschen) Argumenten. lambda beschwert sich darüber, während Proc.new ignoriert zusätzliche Argumente oder betrachtet das Fehlen von Argumenten als Null.

irb(main):021:0> l = -> (x) { x.to_s }
=> #<Proc:0x8b63750@(irb):21 (lambda)>
irb(main):022:0> p = Proc.new { |x| x.to_s}
=> #<Proc:0x8b59494@(irb):22>
irb(main):025:0> l.call
ArgumentError: wrong number of arguments (0 for 1)
        from (irb):21:in `block in irb_binding'
        from (irb):25:in `call'
        from (irb):25
        from /usr/bin/irb:11:in `<main>'
irb(main):026:0> p.call
=> ""
irb(main):049:0> l.call 1, 2
ArgumentError: wrong number of arguments (2 for 1)
        from (irb):47:in `block in irb_binding'
        from (irb):49:in `call'
        from (irb):49
        from /usr/bin/irb:11:in `<main>'
irb(main):050:0> p.call 1, 2
=> "1"

ÜBRIGENS, proc in Ruby 1.8 erzeugt ein Lambda, während es sich in Ruby 1.9+ wie Proc.new was wirklich verwirrend ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X