Die Programmiersprache Ruby (German Edition)
und
until
-Schleifen ist das Schlüsselwort
do
optional und kann durch einen Zeilenumbruch oder ein Semikolon ersetzt werden.
Hier sehen Sie Beispiele für
for
-Schleifen:
# Die Elemente in einem Array ausgeben
array = [1,2,3,4,5]
for element in array
puts element
end
# Schlüssel und Werte in einem Hash ausgeben
hash = {:a=>1, :b=>2, :c=>3}
for key,value in hash
puts "#{key} => #{value}"
end
Die Schleifenvariable oder -variablen ist beziehungsweise sind nicht lokal für die Schleife; sie bleiben auch nach der Existenz der Schleife definiert. Entsprechend existieren auch neue Variablen, die innerhalb des Schleifenrumpfs definiert werden, nach der Existenz der Schleife weiter.
Die Tatsache, dass die
for
-Schleife von der Iteratormethode
each
abhängt, legt den Schluss nahe, dass
for
-Schleifen den Iteratoren stark ähneln. Zum Beispiel könnte die oben gezeigte
for
-Schleife zum Aufzählen der Schlüssel und Werte eines Hash auch unter expliziter Verwendung des Iterators
each
geschrieben werden:
hash = {:a=>1, :b=>2, :c=>3}
hash.each do |key,value|
puts "#{key} => #{value}"
end
Der einzige Unterschied zwischen der
for
-Version der Schleife und der
each
-Version ist, dass der Codeblock, der auf einen Iterator folgt, einen neuen Variablengültigkeitsbereich definiert. Details finden Sie in der Diskussion über Iteratoren weiter unten in diesem Kapitel.
5.3 Iteratoren und Aufzählungsobjekte
while
-,
until
- und
for
-Schleifen sind zwar ein Kernbestandteil der Sprache Ruby, aber es ist üblicher, Schleifen mithilfe spezieller Methoden zu schreiben, die Iteratoren genannt werden. Iteratoren gehören zu den bemerkenswertesten Features von Ruby, und Beispiele wie das folgende kommen häufig in einführenden Ruby-Tutorials vor:
3.times { puts "Danke!" } # Dreimal Dankbarkeit ausdrücken
data.each {|x| puts x } # Jedes Element x von data ausgeben
[1,2,3].map {|x| x*x } # Quadrate der Array-Elemente berechnen
factorial = 1 # Fakulät von n berechnen
2.upto(n) {|x| factorial *= x }
Die Methoden
times
,
each
,
map
und
upto
sind alle Iteratoren, und sie interagieren mit dem Codeblock , der auf sie folgt. Dahinter steckt die komplexe Kontrollstruktur
yield
. Die Anweisung
yield
gibt die Kontrolle von der Iteratormethode vorübergehend an die Methode zurück, die den Interator aufgerufen hat. Genauer gesagt geht der Steuerungsablauf vom Iterator auf denjenigen Codeblock über, der mit dem Aufruf des Iterators verknüpft ist. Sobald das Ende des Blocks erreicht wird, erhält die Iteratormethode die Kontrolle zurück, und die Ausführung geht bei der ersten Anweisung weiter, die auf das
yield
folgt. Um irgendeine Art von Schleifenkonstrukt zu implementieren, wird eine Iteratormethode die Anweisung
yield
üblicherweise mehrmals aufrufen. Abbildung 5.1 demonstriert diesen komplexen Steuerungsablauf. Blöcke und
yield
werden weiter unten in „5.4 Blöcke“ detailliert beschrieben; im Moment konzentrieren wir uns auf die Iteration selbst anstatt auf die Kontrollstruktur, die sie ermöglicht.
Abbildung 5.1 Ein Iterator übergibt die Kontrolle mit yield an seine aufrufende Methode
Wie Sie an den obigen Beispielen gesehen haben, können Blöcke parametrisiert werden. Vertikale Balken (
|
) am Anfang eines Blocks sind wie Klammern in einer Methodendefinition – sie enthalten eine Liste von Parameternamen. Die
yield
-Anweisung ist wie ein Methodenaufruf; darauf folgen null oder mehr Ausdrücke, deren Werte den Blockparametern zugewiesen werden.
5.3.1 Numerische Iteratoren
Die Ruby-Kern-API stellt eine Reihe von Standarditeratoren zur Verfügung. Die Kernel-Methode
loop
verhält sich wie eine Endlosschleife, die ihren zugehörigen Block wiederholt, bis der Block
return
,
break
oder eine andere Anweisung ausführt, die aus der Schleife aussteigt.
----
Iteratoren, die nicht iterieren
Wir verwenden den Begriff Iterator in diesem Buch für jede Methode, die die
yield
-Anweisung verwendet. Sie braucht nicht unbedingt eine Iterations- oder Schleifenfunktion zu erfüllen. [ 21 ] Die Methode
tap
, die (in Ruby 1.9) von der Klasse
Object
definiert wird, ist ein Beispiel dafür. Sie ruft den verknüpften Block einmal auf und übergibt ihm den Empfänger als einziges Argument. Dann gibt sie den Empfänger zurück. Das ist praktisch, um eine Methodenkette »anzuzapfen«, wie im folgenden Code, der
tap
verwendet, um Debug-Meldungen auszugeben:
chars = "Hallo Welt".tap {|x| puts "Originalobjekt: #{x.inspect}"}
.each_char .tap {|x| puts
Weitere Kostenlose Bücher