Die Programmiersprache Ruby (German Edition)
Zeitpunkt, wenn die Proc aufgerufen wird, kann die lexikalisch umgebende Methode bereits zurückgekehrt sein:
def procBuilder(message) # Eine Proc erzeugen und zurückgeben
Proc.new { puts message; return } # return kehrt aus procBuilder zurück.
# Aber procBuilder ist hier bereits zurückgekehrt!
end
def test
puts "Eintritt in die Methode"
p = procBuilder("Eintritt in die Proc")
p.call # Gibt "Eintritt in die Proc" aus und löst LocalJumpError aus!
puts "Ausgang aus der Methode" # Zeile wird nie ausgeführt.
end
test
Indem wir einen Block in ein Objekt konvertieren, können wir das Objekt herumreichen und »außerhalb seines Kontextes« verwenden. Wenn wir das tun, gehen wir das Risiko ein, aus einer Methode zurückzukehren, die bereits zurückgekehrt ist, wie es hier der Fall ist. Wenn das geschieht, löst Ruby einen
LocalJumpError
aus.
Die Lösung für dieses arg konstruierte Beispiel besteht natürlich darin, die unnötige
return
-Anweisung zu entfernen. Aber eine
return
-Anweisung ist nicht immer unnötig, und eine weitere Lösung besteht darin, ein Lambda statt einer Proc zu verwenden. Wie bereits erwähnt, funktionieren Lambdas eher wie Methoden als wie Blöcke. Eine
return
-Anweisung in einem Lambda kehrt daher aus dem Lambda selbst zurück und nicht aus der Methode, die den Erzeugungsort des Lambdas umgibt:
def test
puts "Eintritt in die Methode"
p = lambda { puts "Eintritt in das Lambda"; return }
p.call # Aufruf des Lambdas lässt die Methode nicht zurückkehren.
puts "Ausgang aus der Methode" # Diese Zeile *wird* ausgeführt.
end
test
Die Tatsache, dass
return
in einem Lambda nur aus dem Lambda selbst zurückkehrt, bedeutet, dass wir uns niemals Sorgen über den
LocalJumpError
zu machen brauchen:
def lambdaBuilder(message) # Ein Lambda erzeugen und zurückgeben
lambda { puts message; return } # return kehrt aus dem Lambda zurück.
end
def test
puts "Eintritt in die Methode"
l = lambdaBuilder("Eintritt in das Lambda")
l.call # Gibt "Eintritt in das Lambda" aus
puts "Ausgang aus der Methode" # Diese Zeile wird ausgeführt.
end
test
6.5.5.2 Break in Blöcken, Procs und Lambdas
Abbildung 5.3 demonstrierte das Verhalten der
break
-Anweisung in einem Block; diese sorgt dafür, dass der Block zu seinem Iterator zurückkehrt und dass der Iterator zu der Methode zurückkehrt, die ihn aufgerufen hat. Da Procs wie Blöcke funktionieren, erwarten wir, dass
break
in einer Proc dasselbe tut. Wir können das jedoch nicht leicht prüfen. Wenn wir mit
Proc.new
eine neue Proc erzeugen, ist
Proc.new
der Iterator, aus dem
break
zurückkehrt. Und zu dem Zeitpunkt, zu dem wir das Proc-Objekt aufrufen, ist der Iterator bereits zurückgekehrt. Deshalb ergibt es niemals einen Sinn, auf der obersten Ebene einer mit
Proc.new
erzeugten Proc eine
break
-Anweisung einzusetzen:
def test
puts "Eintritt in die Methode test"
proc = Proc.new { puts "Eintritt in die Proc"; break }
proc.call # LocalJumpError: Iterator ist bereits zurückgekehrt.
puts "Ausgang aus der Methode test"
end
test
Wenn wir ein Proc-Objekt mit einem
&
-Argument der Iteratormethode erstellen, können wir es aufrufen und den Iterator zurückkehren lassen:
def iterator(&proc)
puts "Eintritt in den Iterator"
proc.call # Die Proc aufrufen
puts "Ausgang aus dem Iterator" # Bei break der Proc niemals ausgeführt
end
def test
iterator { puts "Eintritt in die Proc"; break }
end
test
Lambdas sind Methoden ähnlich, so dass es sinnlos ist, eine
break
-Anweisung auf die oberste Ebene eines Lambda zu setzen, wo keine umgebende Schleife oder Iteration verlassen werden kann! Wir könnten erwarten, dass der folgende Code scheitert, weil es in dem Lambda nichts gibt, das
break
verlassen kann. Aber in der Praxis verhält sich das
break
auf der obersten Ebene einfach wie ein
return
:
def test
puts "Eintritt in die Methode test"
lambda = lambda { puts "Eintritt in das Lambda"; break; puts "Ausgang aus dem Lambda" }
lambda.call
puts "Ausgang aus der Methode test"
end
test
6.5.5.3 Andere Steuerungsablaufanweisungen
Eine
next
-Anweisung auf der obersten Ebene eines Blocks, einer Proc oder eines Lambda funktioniert überall gleich: Sie sorgt dafür, dass die
yield
-Anweisung beziehungsweise die
call
-Methode, die den Block, die Proc oder das Lambda aufgerufen hat, zurückkehrt. Wenn auf das
next
ein Ausdruck folgt, wird dieser Ausdruck zum Rückgabewert des Blocks, der Proc oder des Lambda.
redo
funktioniert in Procs und Lambdas ebenfalls gleich: Es
Weitere Kostenlose Bücher