Die Programmiersprache Ruby (German Edition)
Stelle sagt Hallo" # Zeile 7:
f.resume # Zeile 8: Sprung zu Zeile 2
puts "Aufrufende Stelle sagt Tschüss" # Zeile 9:
f.resume # Zeile 10: Sprung zu Zeile 4
# Zeile 11:
Der Rumpf der Fiber wird nicht sofort ausgeführt, wenn sie erzeugt wird, so dass dieser Code eine Fiber, aber keine Ausgabe erzeugt, bis sie Zeile 7 erreicht. Die
resume
- und
Fiber.yield
-Aufrufe übertragen die Kontrolle dann hin und zurück, so dass die Meldungen der Fiber und der aufrufenden Stelle abwechselnd kommen. Der Code erzeugt folgende Ausgabe:
Aufrufende Stelle sagt Hallo
Fiber sagt Hallo
Aufrufende Stelle sagt Tschüss
Fiber sagt Tschüss
Es lohnt sich, darauf hinzuweisen, dass das von
Fiber.yield
durchgeführte »Yielding« etwas ganz anderes ist als das, was die Anweisung
yield
durchführt.
Fiber.yield
gibt die Kontrolle aus der aktuellen Fiber an die aufrufende Stelle zurück. Die
yield
-Anweisung übergibt die Kontrolle dagegen von einer Iteratormethode an den mit der Methode verknüpften Block.
5.8.2.1 Fiber-Argumente und -Rückgabewerte
Fiber und ihre aufrufenden Stellen können Daten durch die Argumente austauschen sowie über
resume
und
yield
Werte zurückgeben. Die Argumente des ersten Aufrufs von
resume
werden an den Block übergeben, der mit der Fiber verknüpft ist: Sie werden zu den Werten der Blockparameter. Bei nachfolgenden Aufrufen werden die Argumente von
resume
zu den Rückgabewerten von
Fiber.yield
. Umgekehrt werden etwaige Argumente von
Fiber.yield
zum Rückgabewert von
resume
. Und wenn der Block beendet wird, wird der Wert des zuletzt ausgewerteten Ausdrucks ebenfalls zum Rückgabewert von
resume
. Der folgende Code demonstriert das:
f = Fiber.new do |message|
puts "Aufrufende Stelle sagte: #{message}"
message2 = Fiber.yield("Hallo") # "Hallo" Rückgabewert des ersten resume
puts "Aufrufende Stelle sagte: #{message2}"
"Gut" # "Gut" Rückgabewert des zweiten resume
end
response = f.resume("Hallo") # "Hallo" an Block übergeben
puts "Fiber sagte: #{response}"
response2 = f.resume("Wie geht's?") # "Wie geht's?" Rückgabewert von Fiber.yield
puts "Fiber sagte: #{response2}"
Die aufrufende Stelle übergibt zwei Meldungen an die Fiber, und die Fiber gibt zwei Antworten an die aufrufende Stelle zurück. Die Ausgabe ist
Aufrufende Stelle sagte: Hallo
Fiber sagte: Hallo
Aufrufende Stelle sagte: Wie geht's?
Fiber sagte: Gut
Im Code der aufrufenden Stelle sind die Meldungen stets Argumente für
resume
, und die Antworten sind jeweils die Rückgabewerte dieser Methode. Im Rumpf der Fiber werden alle Meldungen außer der ersten als Rückgabewert von
Fiber.yield
empfangen, und alle Antworten außer der letzten werden als Argumente für
Fiber.yield
verwendet. Die erste Meldung wird durch Block-Parameter empfangen, und die letzte Antwort ist der Rückgabewert des Blocks selbst.
5.8.2.2 Generatoren durch Fiber implementieren
Die bisher gezeigten Fiber-Beispiele waren nicht sonderlich realistisch. Jetzt demonstrieren wir einige typischere Verwendungszwecke. Zuerst schreiben wir einen Fibonacci-Zahlengenerator – ein Fiber-Objekt, das bei jedem Aufruf von
resume
ein weiteres Mitglied der Fibonacci-Folge zurückgibt:
# Eine Fiber zur Berechnung von Fibonacci-
# Zahlen zurückgeben
def fibonacci_generator(x0,y0) # Basis der Folge x0,y0
Fiber.new do
x,y = x0, y0 # x und y initialisieren
loop do # Diese Fiber läuft endlos.
Fiber.yield y # Nächste Zahl in der Folge weitergeben
x,y = y,x+y # x und y aktualisieren
end
end
end
g = fibonacci_generator(0,1) # Einen Generator erzeugen
10.times { print g.resume, " " } # Und verwenden
Der obige Code gibt die ersten zehn Fibonacci-Zahlen aus:
1 1 2 3 5 8 13 21 34 55
Da
Fiber
eine verwirrende Kontrollstruktur ist, möchten wir ihre API vielleicht lieber verbergen, wenn wir Generatoren schreiben. Hier sehen Sie eine weitere Version eines Fibonacci-Zahlengenerators. Er definiert seine eigene Klasse und definiert dieselbe
next
- und
rewind
-API wie Enumeratoren:
class FibonacciGenerator
def initialize
@x,@y = 0,1
@fiber = Fiber.new do
loop do
@x,@y = @y, @x+@y
Fiber.yield @x
end
end
end
def next # Nächste Fibonacci-Zahl zurückgeben
@fiber.resume
end
def rewind # Reihe starten
@x,@y = 0,1
end
end
g = FibonacciGenerator.new # Generator erzeugen
10.times { print g.next, " " } # Erste 10 Zahlen ausgeben
g.rewind; puts # Neu starten, in neuer Zeile
10.times { print g.next, " " } # Die ersten 10 erneut ausgeben
Beachten Sie, dass wir
Weitere Kostenlose Bücher