Die Programmiersprache Ruby (German Edition)
setzt die Steuerung zurück an den Anfang der Proc beziehungsweise des Lambda.
retry
ist in Procs und Lambdas niemals erlaubt: Seine Verwendung verursacht einen
LocalJumpError
.
raise
verhält sich in Blöcken, Procs und Lambdas identisch. Ausnahmen werden stets den Aufruf-Stack hinaufgereicht. Wenn ein Block, eine Proc oder ein Lambda eine Ausnahme auslöst und es keine lokale
rescue
-Klausel gibt, wird die Ausnahme zuerst an die Methode weitergereicht, die den Block mit
yield
beziehungsweise die Proc oder das Lambda mit
call
aufgerufen hat.
6.5.5.4 Argumentübergabe an Procs oder Lambdas
Der Aufruf eines Blocks mit
yield
ähnelt dem Aufruf einer Methode, ist aber nicht dasselbe. Es gibt Unterschiede bezüglich der Art und Weise, wie die Argumentwerte im Aufruf den im Block beziehungsweise in der Methode deklarierten Argumentvariablen zugewiesen werden. Die
yield
-Anweisung verwendet Yield-Semantik , während Methodenaufrufe Aufrufsemantik verwenden. yield-Semantik ähnelt der parallelen Wertzuweisung und wird in „5.4.4 Argumente an einen Block übergeben“ beschrieben. Wie Sie vielleicht bereits vermutet haben, verwendet der Aufruf eines Blocks
yield
-Semantik, während der Aufruf eines Lambda Aufrufsemantik verwendet:
p = Proc.new {|x,y| print x,y }
p.call(1) # x,y=1: nil für fehlendes Rvalue: Gibt 1nil aus
p.call(1,2) # x,y=1,2: 2 Lvalues, 2 Rvalues: Gibt 12 aus
p.call(1,2,3) # x,y=1,2,3: Zusätzl. Rvalue nicht beachtet: Gibt 12 aus
p.call([1,2]) # x,y=[1,2]: Array automatisch entpackt: Gibt 12 aus
Dieser Code demonstriert, dass die
call
-Methode einer Proc die erhaltenen Argumente flexibel handhabt: Zusätzliche Argumente werden stillschweigend weggelassen, für fehlende Argumente wird ebenso stillschweigend
nil
hinzugefügt, und sogar Arrays werden entpackt. (Oder mehrere Argumente werden in ein einzelnes Array gepackt, wenn die Proc nur ein einzelnes Argument erwartet; das wurde hier nicht demonstriert.)
Lambdas sind nicht so flexibel; genau wie Methoden müssen sie exakt mit der Anzahl von Argumenten aufgerufen werden, mit der sie deklariert wurden:
l = lambda {|x,y| print x,y }
l.call(1,2) # Das funktioniert.
l.call(1) # Falsche Anzahl von Argumenten
l.call(1,2,3) # Falsche Anzahl von Argumenten
l.call([1,2]) # Falsche Anzahl von Argumenten
l.call(*[1,2]) # Funktioniert: Expliziter Splat zum Entpacken des Array
6.6 Closures
In Ruby sind Procs und Lambdas Closures . Der Begriff »Closure« stammt aus den frühen Tagen der Informatik; er bezieht sich auf ein Objekt, das sowohl eine aufrufbare Funktion als auch eine Variablenbindung für diese Funktion ist. Wenn Sie eine Proc oder ein Lambda erzeugen, enthält das resultierende
Proc
-Objekt nicht nur den ausführbaren Block, sondern auch Bindungen für alle Variablen, die von diesem Block verwendet werden.
Sie wissen bereits, dass Blöcke lokale Variablen und Methodenargumente nutzen können, die außerhalb des Blocks definiert werden. Im folgenden Code verwendet der mit dem Iterator
collect
verknüpfte Block beispielsweise das Methodenargument
n
:
# Jedes Element des Arrays data mit n multiplizieren
def multiply(data, n)
data.collect {|x| x*n }
end
puts multiply([1,2,3], 2) # Gibt 2,4,6 aus
Interessanter und möglicherweise sogar überraschend ist die Tatsache, dass der Block bei Umwandlung in eine Proc oder ein Lambda selbst dann noch auf
n
zugreifen könnte, wenn die Methode, für die
n
ein Argument ist, bereits zurückgekehrt wäre. Der folgende Code demonstriert das:
# Ein Lambda zurückgeben, das das Argument n enthält oder "umschließt"
def multiplier(n)
lambda {|data| data.collect{|x| x*n } }
end
doubler = multiplier(2) # Ein Lambda erhalten, das verdoppeln kann
puts doubler.call([1,2,3]) # Gibt 2,4,6 aus
Die Methode
multiplier
gibt ein Lambda zurück. Da dieses Lambda außerhalb des Gültigkeitsbereichs verwendet wird, in dem es definiert wurde, nennen wir es eine Closure; es kapselt oder »umschließt« (oder enthält) die Bindung für das Methodenargument
n
.
6.6.1 Closures und gemeinsame Variablen
Es ist wichtig, zu verstehen, dass eine Closure nicht den Wert der Variablen enthält, auf die es verweist – es enthält die eigentlichen Variablen und verlängert deren Lebensdauer. Eine andere Interpretationsmöglichkeit ist, dass die in einem Lambda oder einer Proc verwendeten Variablen nicht statisch gebunden werden, wenn das Lambda oder die Proc erzeugt wird. Stattdessen sind die Bindungen dynamisch, und die Werte der Variablen
Weitere Kostenlose Bücher