Die Programmiersprache Ruby (German Edition)
den Block verwenden, wird der Block mit dem letzten Methodenargument statt mit der Methode selbst verknüpft, was Sie wahrscheinlich nicht wollen. Um das zu vermeiden, setzen Sie Klammern um die Argumente oder begrenzen Sie den Block mit
do
und
end
:
1.upto(3) {|x| puts x } # Klammern und geschweifte Klammern: OK
1.upto 3 do |x| puts x end # Keine Klammern; Block begrenzt durch do/end
1.upto 3 {|x| puts x } # Syntaxfehler: Versuch, einen Block an 3 zu übergeben!
Blöcke können parametrisiert werden, genau wie Methoden. Blockparameter werden durch Kommata getrent und durch ein Paar vertikaler Balken (
|
) begrenzt, aber ansonsten sind sie den Methodenparametern sehr ähnlich:
# Iterator Hash.each übergibt zwei Argumente an seinen Block
hash.each do |key, value| # Für jedes (key,value)-Paar im Hash
puts "#{key}: #{value}" # Schlüssel und Wert ausgeben
end # Ende des Blocks
Es ist eine gängige Konvention, die Blockparameter in dieselbe Zeile zu schreiben wie den Methodenaufruf und die öffnende geschweifte Klammer beziehungsweise das Schlüsselwort
do
, aber das ist keine Bedingung der Syntax.
5.4.2 Der Wert eines Blocks
In den bisher in diesem Kapitel gezeigten Iteratorbeispielen hat die Iteratormethode jeweils Werte an ihren verknüpften Block übergeben, den vom Block zurückgegebenen Wert aber ignoriert. Das ist allerdings nicht immer der Fall. Betrachten Sie die Methode
Array.sort
. Wenn Sie einen Block mit dieser Methode verknüpfen, übergibt sie Wertepaare an den Block, und es ist Aufgabe des Blocks, diese zu sortieren. Der Rückgabewert des Blocks (
−1
,
0
oder
1
) gibt die Sortierreihenfolge der beiden Argumente an. Der »Rückgabewert« des Blocks ist für die Iteratormethode als Wert der
yield
-Anweisung verfügbar.
Der »Rückgabewert« eines Blocks ist einfach der Wert des letzten Ausdrucks, der in dem Block ausgewertet wurde. Um also ein Array von Wörtern vom längsten bis zum kürzesten zu sortieren, könnten wir schreiben:
# "Rückgabewert" des Blocks ist die relative Sortierung zweier Wörter.
words.sort! {|x,y| y <=> x }
Wir haben den Begriff »Rückgabewert« aus einem sehr wichtigen Grund in Anführungszeichen gesetzt: Sie sollten normalerweise nicht das Schlüsselwort
return
verwenden, um aus einem Block zurückzukehren. Ein
return
innerhalb eines Blocks bewirkt, dass die enthaltende Methode (nicht die Iteratormethode, die den Block aufruft, sondern die Methode, deren Teil der Block ist) zurückkehrt. Es kommt natürlich vor, dass genau dies das gewünschte Verhalten ist. Aber verwenden Sie
return
nicht, wenn Sie aus einem Block zu der Methode zurückkehren möchten, die
yield
aufgerufen hat. Wenn Sie erzwingen müssen, dass ein Block zu der aufrufenden Methode zurückkehrt, bevor er den letzten Ausdruck erreicht, oder wenn Sie mehr als einen Wert zurückgeben möchten, dann können Sie
next
anstelle von
return
verwenden. (
return
,
next
und die verwandte Anweisung
break
werden detailliert in „5.5 Den Steuerungsablauf modifizieren“ erläutert.) Hier sehen Sie ein Beispiel, das
next
verwendet, um aus dem Block zurückzukehren:
array.collect do |x|
next 0 if x == nil # Vorzeitiges Ende, wenn x nil ist
next x, x*x # Zwei Werte zurückgeben
end
Beachten Sie, dass es nicht besonders üblich ist,
next
auf diese Weise zu verwenden. Der obige Code lässt sich leicht ohne
next
umschreiben:
array.collect do |x|
if x == nil
0
else
[x, x*x]
end
end
5.4.3 Blöcke und Gültigkeitsbereiche von Variablen
Blöcke definieren einen neuen Gültigkeitsbereich für Variablen: Variablen, die innerhalb eines Blocks erzeugt werden, existieren nur innerhalb dieses Blocks, und außerhalb des Blocks wird ihre Definition aufgehoben. Seien Sie jedoch vorsichtig: Die lokalen Variablen in einer Methode stehen allen Blöcken innerhalb dieser Methode stets zur Verfügung. Wenn ein Block also einer Variablen einen Wert zuweist, die bereits außerhalb des Blocks definiert ist, wird keine neue blocklokale Variable erzeugt, sondern der bereits existierenden Variablen wird ein neuer Wert zugewiesen. Manchmal ist das genau das erwünschte Verhalten:
total = 0
data.each {|x| total += x } # Summe der Elemente im Array data
puts total # Diese Summe ausgeben
Manchmal dagegen möchten wir keine Variablen des umgebenden Gültigkeitsbereichs modifizieren, tun es aber versehentlich. Auf dieses Problem müssen Sie besonders bei Block-Parametern in Ruby 1.8 achten. Wenn ein Block-Parameter in Ruby 1.8 denselben Namen
Weitere Kostenlose Bücher