Ein Unterschied besteht in der Art und Weise, wie sie mit Argumenten umgehen. Erstellen eines Prozesses mit proc {}und Proc.new {}sind gleichwertig. lambda {}Wenn Sie jedoch verwenden, erhalten Sie einen Prozess, der die Anzahl der an ihn übergebenen Argumente überprüft. Von ri Kernel#lambda:
Entspricht Proc.new , außer dass die resultierenden Proc-Objekte die Anzahl der beim Aufruf übergebenen Parameter überprüfen.
Ein Beispiel:
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)
Wie Ken betont, gibt die Verwendung returnin einem Lambda den Wert dieses Lambdas zurück, während die Verwendung returnin einem Proc vom umschließenden Block zurückkehrt.
Für die meisten schnellen Verwendungen sind sie also gleich, aber wenn Sie eine automatische strenge Argumentprüfung wünschen (was manchmal auch beim Debuggen hilfreich sein kann) oder wenn Sie die returnAnweisung verwenden müssen, um den Wert des Prozesses zurückzugeben, verwenden Sie lambda.
Wäre es richtig zu sagen, dass Lambdas Methoden sehr ähnlich sind (Check-Argumente und Rückgabe werden von ihnen zurückgegeben), während Procs Blöcken sehr ähnlich sind (Argumente werden nicht überprüft und eine Rückgabe wird von der enthaltenen Methode oder Lambda zurückgegeben)?
Pedz
Ich war bei Gott weiß, wie viele Websites und Artikel es inzwischen gibt, und niemand scheint über die Nützlichkeit von Procs vs. Methoden vs. Lambdas zu sprechen. Jede Erklärung liefert nur ein haarspaltendes Detail darüber, wie unterschiedlich Rückgabewerte usw. sind, aber keine darüber, warum es wichtig ist. Im Moment muss ich zu dem Schluss kommen, dass dies ein Design-Chaos in Ruby ist.
ankush981
75
Der wahre Unterschied zwischen procs und lambdas hat alles mit Schlüsselwörtern für den Kontrollfluss zu tun. Ich spreche von return, raise, break, redo, retryusw. - diese Steuerwörter. Angenommen, Sie haben eine return-Anweisung in einem Proc. Wenn Sie Ihren Prozess aufrufen, werden Sie nicht nur aus dem Prozess entfernt, sondern es wird auch von der einschließenden Methode zurückgekehrt, z.
Das Finale putsin der Methode wurde nie ausgeführt, da uns das returndarin enthaltene Proc aus der Methode geworfen hat, als wir unseren Proc aufgerufen haben . Wenn wir jedoch unseren Proc in ein Lambda umwandeln, erhalten wir Folgendes:
def my_method
puts "before proc"
my_proc = lambda do
puts "inside proc"returnend
my_proc.call
puts "after proc"end
my_method
shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
after proc
Die Rückgabe innerhalb des Lambda entleert uns nur aus dem Lambda selbst und die einschließende Methode wird weiter ausgeführt. Die Art und Weise, wie Kontrollfluss-Schlüsselwörter in procs und lambdas behandelt werden, ist der Hauptunterschied zwischen ihnen
Zunächst lambdaüberprüft a die Anzahl der übergebenen Argumente, während a procdies nicht tut. Dies bedeutet, dass a lambdaeinen Fehler auslöst, wenn Sie ihm die falsche Anzahl von Argumenten übergeben, während a procunerwartete Argumente ignoriert und zuweistnil fehlenden .
Zweitens, wenn a lambdazurückkehrt, gibt es die Kontrolle an die aufrufende Methode zurück. Wenn a proczurückkehrt, geschieht dies sofort, ohne zur aufrufenden Methode zurückzukehren.
Sehen Sie sich den folgenden Code an, um zu sehen, wie dies funktioniert. Unsere erste Methode nennt a proc; der zweite ruft a lambda.
def batman_ironman_proc
victor =Proc.new {return"Batman will win!"}
victor.call
"Iron Man will win!"end
puts batman_ironman_proc # prints "Batman will win!"def batman_ironman_lambda
victor = lambda {return"Batman will win!"}
victor.call
"Iron Man will win!"end
puts batman_ironman_lambda # prints "Iron Man will win!"
Sehen Sie, wie proc"Batman wird gewinnen!" Sagt, weil es sofort zurückkehrt, ohne zur Methode batman_ironman_proc zurückzukehren.
Unsere lambdaMethode kehrt jedoch nach dem Aufruf zur Methode zurück, sodass die Methode den letzten Code zurückgibt, den sie auswertet: "Iron Man wird gewinnen!"
1. Lambdas überprüfen die Anzahl der Argumente, Procs nicht
lam = lambda {|x| puts x }# creates a lambda that takes 1 argument
lam.call(2)# prints out 2
lam.call # ArgumentError: wrong number of arguments (0 for 1)
lam.call(1,2,3)# ArgumentError: wrong number of arguments (3 for 1)
Im Gegensatz dazu ist es Procs egal, ob ihnen die falsche Anzahl von Argumenten übergeben wird.
proc =Proc.new {|x| puts x }# creates a proc that takes 1 argument
proc.call(2)# prints out 2
proc.call # returns nil
proc.call(1,2,3)# prints out 1 and forgets about the extra arguments
2. Lambdas und procs behandeln das Schlüsselwort 'return' unterschiedlich
'return' innerhalb eines Lambda löst den Code direkt außerhalb des Lambda-Codes aus
Und um Ihre andere Frage zu beantworten, welche und wann? Ich werde @jtbandes folgen, wie er erwähnt hat
Für die meisten schnellen Verwendungen sind sie also gleich, aber wenn Sie eine automatische strenge Argumentprüfung wünschen (was manchmal auch beim Debuggen hilfreich sein kann) oder wenn Sie die return-Anweisung verwenden müssen, um den Wert des Prozesses zurückzugeben, verwenden Sie Lambda.
Im Allgemeinen sind Lambdas intuitiver als Procs, da sie Methoden ähnlicher sind. Sie sind ziemlich streng in Bezug auf Arity und werden einfach beendet, wenn Sie Return anrufen. Aus diesem Grund verwenden viele Rubyisten Lambdas als erste Wahl, es sei denn, sie benötigen die spezifischen Funktionen von Procs.
Procs: Objekte der Klasse Proc. Wie Blöcke werden sie in dem Bereich ausgewertet, in dem sie definiert sind.
Lambdas: Auch Objekte der Klasse, Procaber subtil anders als normale Procs. Sie sind Verschlüsse wie Blöcke und Prozesse und werden als solche in dem Bereich bewertet, in dem sie definiert sind.
a = proc { |x| x 2 }ist das gleiche wiea = Proc.new { |x| x 2 }
lacostenycoder
1
Hier ist ein anderer Weg, dies zu verstehen.
Ein Block ist ein Codeabschnitt, der an den Aufruf eines Aufrufs einer Methode für ein Objekt angehängt ist. Im folgenden Beispiel ist self eine Instanz einer anonymen Klasse, die von ActionView :: Base im Rails-Framework (das selbst viele Hilfsmodule enthält) erbt. Karte ist eine Methode, die wir selbst aufrufen. Wir übergeben der Methode ein Argument und hängen den Block immer an das Ende des Methodenaufrufs an:
self.card :contacts do|c|// a chunk of valid ruby code
end
Ok, wir übergeben einen Codeabschnitt an eine Methode. Aber wie nutzen wir diesen Block? Eine Möglichkeit besteht darin, den Codeabschnitt in ein Objekt umzuwandeln. Ruby bietet drei Möglichkeiten, um einen Codeabschnitt in ein Objekt umzuwandeln
# lambda> l = lambda {|a| a +1}> l.call(1)=>2# Proc.new> l2=Proc.new {|a| a +1}> l2.call(1)=>2# & as the last method argument with a local variable namedef add(&block)end
In der obigen Methode konvertiert & den an die Methode übergebenen Block in ein Objekt und speichert dieses Objekt im lokalen Variablenblock. In der Tat können wir zeigen, dass es das gleiche Verhalten wie Lambda und Proc.new hat:
def add(&block)
block
end
l3 = add {|a| a +1}
l3.call(1)=>2
Das ist wichtig. Wenn Sie einen Block an eine Methode übergeben und mit & konvertieren, verwendet das erstellte Objekt Proc.new, um die Konvertierung durchzuführen.
Beachten Sie, dass ich die Verwendung von "proc" als Option vermieden habe. Das liegt daran, dass es Ruby 1.8 ist, dasselbe wie Lambda und in Ruby 1.9 dasselbe wie Proc.new und in allen Ruby-Versionen sollte es vermieden werden.
Dann fragen Sie sich, was der Unterschied zwischen Lambda und Proc.new ist.
Erstens verhält sich Lambda in Bezug auf die Parameterübergabe wie ein Methodenaufruf. Es wird eine Ausnahme ausgelöst, wenn Sie die falsche Anzahl von Argumenten übergeben. Im Gegensatz dazu verhält sich Proc.new wie eine parallele Zuweisung. Alle nicht verwendeten Argumente werden in nil konvertiert:
> l = lambda {|a,b| puts "#{a} + #{b}"}=>#<Proc:0x007fbffcb47e40@(irb):19 (lambda)> > l.call(1)ArgumentError: wrong number of arguments (1for2)> l2 =Proc.new {|a,b| puts "#{a} + #{b}"}=>#<Proc:0x007fbffcb261a0@(irb):21> > l2.call(1)1+
Zweitens behandeln Lambda und Proc.new das Schlüsselwort return unterschiedlich. Wenn Sie innerhalb von Proc.new eine Rückgabe durchführen, wird diese tatsächlich von der einschließenden Methode, dh dem umgebenden Kontext, zurückgegeben. Wenn Sie von einem Lambda-Block zurückkehren, kehrt er nur vom Block zurück, nicht von der einschließenden Methode. Grundsätzlich verlässt es den Aufruf des Blocks und setzt die Ausführung mit dem Rest der einschließenden Methode fort.
>def add(a,b)
l =Proc.new {return a + b}
l.call
puts "now exiting method"end> add(1,1)=>2# NOTICE it never prints the message "now exiting method">def add(a,b)
l = lambda {return a + b }
l.call
puts "now exiting method"end> add(1,1)=> now exiting method # NOTICE this time it prints the message "now exiting method"
Warum also dieser Verhaltensunterschied? Der Grund dafür ist, dass wir mit Proc.new Iteratoren im Kontext einschließender Methoden verwenden und logische Schlussfolgerungen ziehen können. Schauen Sie sich dieses Beispiel an:
>def print(max)[1,2,3,4,5].each do|val|
puts val
returnif val > max
endend> print(3)1234
Wir erwarten, dass beim Aufrufen von return innerhalb des Iterators diese von der einschließenden Methode zurückgegeben wird. Denken Sie daran, dass die an Iteratoren übergebenen Blöcke mit Proc.new in Objekte konvertiert werden. Wenn Sie also return verwenden, wird die einschließende Methode beendet.
Sie können sich Lambdas als anonyme Methoden vorstellen. Sie isolieren einzelne Codeblöcke in ein Objekt, das wie eine Methode behandelt werden kann. Stellen Sie sich ein Lambda letztendlich als anomische Methode und Proc.new als Inline-Code vor.
Der Unterschied zwischen proc und lambda besteht darin, dass proc nur eine Kopie des Codes ist, dessen Argumente nacheinander ersetzt werden, während lambda eine Funktion wie in anderen Sprachen ist. (Verhalten der Rückgabe, Argumentprüfung)
return
Aussage inproc
versus zurückkehrtlambda
.Antworten:
Ein Unterschied besteht in der Art und Weise, wie sie mit Argumenten umgehen. Erstellen eines Prozesses mit
proc {}
undProc.new {}
sind gleichwertig.lambda {}
Wenn Sie jedoch verwenden, erhalten Sie einen Prozess, der die Anzahl der an ihn übergebenen Argumente überprüft. Vonri Kernel#lambda
:Ein Beispiel:
Wie Ken betont, gibt die Verwendung
return
in einem Lambda den Wert dieses Lambdas zurück, während die Verwendungreturn
in einem Proc vom umschließenden Block zurückkehrt.Für die meisten schnellen Verwendungen sind sie also gleich, aber wenn Sie eine automatische strenge Argumentprüfung wünschen (was manchmal auch beim Debuggen hilfreich sein kann) oder wenn Sie die
return
Anweisung verwenden müssen, um den Wert des Prozesses zurückzugeben, verwenden Sielambda
.quelle
Der wahre Unterschied zwischen procs und lambdas hat alles mit Schlüsselwörtern für den Kontrollfluss zu tun. Ich spreche von
return
,raise
,break
,redo
,retry
usw. - diese Steuerwörter. Angenommen, Sie haben eine return-Anweisung in einem Proc. Wenn Sie Ihren Prozess aufrufen, werden Sie nicht nur aus dem Prozess entfernt, sondern es wird auch von der einschließenden Methode zurückgekehrt, z.Das Finale
puts
in der Methode wurde nie ausgeführt, da uns dasreturn
darin enthaltene Proc aus der Methode geworfen hat, als wir unseren Proc aufgerufen haben . Wenn wir jedoch unseren Proc in ein Lambda umwandeln, erhalten wir Folgendes:Die Rückgabe innerhalb des Lambda entleert uns nur aus dem Lambda selbst und die einschließende Methode wird weiter ausgeführt. Die Art und Weise, wie Kontrollfluss-Schlüsselwörter in procs und lambdas behandelt werden, ist der Hauptunterschied zwischen ihnen
quelle
Es gibt nur zwei Hauptunterschiede.
lambda
überprüft a die Anzahl der übergebenen Argumente, während aproc
dies nicht tut. Dies bedeutet, dass alambda
einen Fehler auslöst, wenn Sie ihm die falsche Anzahl von Argumenten übergeben, während aproc
unerwartete Argumente ignoriert und zuweistnil
fehlenden .lambda
zurückkehrt, gibt es die Kontrolle an die aufrufende Methode zurück. Wenn aproc
zurückkehrt, geschieht dies sofort, ohne zur aufrufenden Methode zurückzukehren.Sehen Sie sich den folgenden Code an, um zu sehen, wie dies funktioniert. Unsere erste Methode nennt a
proc
; der zweite ruft alambda
.Sehen Sie, wie
proc
"Batman wird gewinnen!" Sagt, weil es sofort zurückkehrt, ohne zur Methode batman_ironman_proc zurückzukehren.Unsere
lambda
Methode kehrt jedoch nach dem Aufruf zur Methode zurück, sodass die Methode den letzten Code zurückgibt, den sie auswertet: "Iron Man wird gewinnen!"quelle
# Proc Beispiele
# Lambda-Beispiele
Unterschiede zwischen Procs und Lambdas
Bevor ich auf die Unterschiede zwischen Procs und Lambdas eingehe, ist es wichtig zu erwähnen, dass beide Proc-Objekte sind.
Lambdas sind jedoch ein anderer "Geschmack" von Procs. Dieser geringfügige Unterschied wird bei der Rückgabe der Objekte angezeigt.
1. Lambdas überprüfen die Anzahl der Argumente, Procs nicht
Im Gegensatz dazu ist es Procs egal, ob ihnen die falsche Anzahl von Argumenten übergeben wird.
2. Lambdas und procs behandeln das Schlüsselwort 'return' unterschiedlich
'return' innerhalb eines Lambda löst den Code direkt außerhalb des Lambda-Codes aus
'return' innerhalb eines Prozesses löst den Code außerhalb der Methode aus, in der der Prozess ausgeführt wird
Und um Ihre andere Frage zu beantworten, welche und wann? Ich werde @jtbandes folgen, wie er erwähnt hat
Ursprünglich hier gepostet
quelle
Im Allgemeinen sind Lambdas intuitiver als Procs, da sie Methoden ähnlicher sind. Sie sind ziemlich streng in Bezug auf Arity und werden einfach beendet, wenn Sie Return anrufen. Aus diesem Grund verwenden viele Rubyisten Lambdas als erste Wahl, es sei denn, sie benötigen die spezifischen Funktionen von Procs.
Procs: Objekte der Klasse
Proc
. Wie Blöcke werden sie in dem Bereich ausgewertet, in dem sie definiert sind. Lambdas: Auch Objekte der Klasse,Proc
aber subtil anders als normale Procs. Sie sind Verschlüsse wie Blöcke und Prozesse und werden als solche in dem Bereich bewertet, in dem sie definiert sind.Proc erstellen
Lambda erstellen
b = lambda { |x| x 2
}}quelle
a = proc { |x| x 2 }
ist das gleiche wiea = Proc.new { |x| x 2 }
Hier ist ein anderer Weg, dies zu verstehen.
Ein Block ist ein Codeabschnitt, der an den Aufruf eines Aufrufs einer Methode für ein Objekt angehängt ist. Im folgenden Beispiel ist self eine Instanz einer anonymen Klasse, die von ActionView :: Base im Rails-Framework (das selbst viele Hilfsmodule enthält) erbt. Karte ist eine Methode, die wir selbst aufrufen. Wir übergeben der Methode ein Argument und hängen den Block immer an das Ende des Methodenaufrufs an:
Ok, wir übergeben einen Codeabschnitt an eine Methode. Aber wie nutzen wir diesen Block? Eine Möglichkeit besteht darin, den Codeabschnitt in ein Objekt umzuwandeln. Ruby bietet drei Möglichkeiten, um einen Codeabschnitt in ein Objekt umzuwandeln
In der obigen Methode konvertiert & den an die Methode übergebenen Block in ein Objekt und speichert dieses Objekt im lokalen Variablenblock. In der Tat können wir zeigen, dass es das gleiche Verhalten wie Lambda und Proc.new hat:
Das ist wichtig. Wenn Sie einen Block an eine Methode übergeben und mit & konvertieren, verwendet das erstellte Objekt Proc.new, um die Konvertierung durchzuführen.
Beachten Sie, dass ich die Verwendung von "proc" als Option vermieden habe. Das liegt daran, dass es Ruby 1.8 ist, dasselbe wie Lambda und in Ruby 1.9 dasselbe wie Proc.new und in allen Ruby-Versionen sollte es vermieden werden.
Dann fragen Sie sich, was der Unterschied zwischen Lambda und Proc.new ist.
Erstens verhält sich Lambda in Bezug auf die Parameterübergabe wie ein Methodenaufruf. Es wird eine Ausnahme ausgelöst, wenn Sie die falsche Anzahl von Argumenten übergeben. Im Gegensatz dazu verhält sich Proc.new wie eine parallele Zuweisung. Alle nicht verwendeten Argumente werden in nil konvertiert:
Zweitens behandeln Lambda und Proc.new das Schlüsselwort return unterschiedlich. Wenn Sie innerhalb von Proc.new eine Rückgabe durchführen, wird diese tatsächlich von der einschließenden Methode, dh dem umgebenden Kontext, zurückgegeben. Wenn Sie von einem Lambda-Block zurückkehren, kehrt er nur vom Block zurück, nicht von der einschließenden Methode. Grundsätzlich verlässt es den Aufruf des Blocks und setzt die Ausführung mit dem Rest der einschließenden Methode fort.
Warum also dieser Verhaltensunterschied? Der Grund dafür ist, dass wir mit Proc.new Iteratoren im Kontext einschließender Methoden verwenden und logische Schlussfolgerungen ziehen können. Schauen Sie sich dieses Beispiel an:
Wir erwarten, dass beim Aufrufen von return innerhalb des Iterators diese von der einschließenden Methode zurückgegeben wird. Denken Sie daran, dass die an Iteratoren übergebenen Blöcke mit Proc.new in Objekte konvertiert werden. Wenn Sie also return verwenden, wird die einschließende Methode beendet.
Sie können sich Lambdas als anonyme Methoden vorstellen. Sie isolieren einzelne Codeblöcke in ein Objekt, das wie eine Methode behandelt werden kann. Stellen Sie sich ein Lambda letztendlich als anomische Methode und Proc.new als Inline-Code vor.
quelle
Ein hilfreicher Beitrag zu Ruby Guides: Blöcke, Procs & Lambdas
quelle
Der Unterschied zwischen proc und lambda besteht darin, dass proc nur eine Kopie des Codes ist, dessen Argumente nacheinander ersetzt werden, während lambda eine Funktion wie in anderen Sprachen ist. (Verhalten der Rückgabe, Argumentprüfung)
quelle