Die Programmiersprache Ruby (German Edition)
Methodenaufrufe.) Klammern um die Argumente sind optional. Sie können
*
verwenden, um ein Array in einzelne Argumente zu entpacken.
yield
erlaubt Ihnen sogar, ein Hash-Literal ohne die umgebenden Klammern zu übergeben. Anders als auf einen Methodenaufruf kann auf einen
yield
-Ausdruck jedoch kein Block folgen. Sie können einem Block keinen Block übergeben.
Wenn eine Methode ohne einen Block aufgerufen wird, ist es ein Fehler, dass diese Methode
yield
aufruft, weil es kein Ziel für dieses
yield
gibt. Manchmal möchten Sie eine Methode schreiben, die einen Block aufruft, falls einer vorhanden ist, aber eine Standardaktion durchführt (eine andere, als einen Fehler auszulösen), wenn sie ohne Block aufgerufen wird. Verwenden Sie dazu
block_given?
, um herauszufinden, ob ein Block mit dem Aufruf verbunden ist.
block_given?
und das Synonym
iterator?
sind Kernel-Methoden, so dass sie sich wie globale Funktionen verhalten. Hier sehen Sie ein Beispiel:
# Ein Array mit n Elementen in der Fom m*i+c zurückgeben
# Falls Block vorhanden, auch jedes Element an Block übergeben
def sequence(n, m, c)
i, s = 0, [] # Variablen initialisieren
while(i < n) # n-mal wiederholen
y = m*i + c # Wert berechnen
yield y if block_given? # yield, falls Block vorhanden
s << y # Den Wert speichern
i += 1
end
s # Das Array mit Werten zurückgeben
end
5.3.4 Enumeratoren
Ein Enumerator ist ein Enumerable-Objekt, dessen Aufgabe es ist, ein anderes Objekt aufzuzählen. Um Enumeratoren in Ruby 1.8 zu verwenden, müssen Sie
require 'enumerator'
aufrufen. In Ruby 1.9 sind Enumeratoren eingebaut, und kein
require
wird benötigt. (Wie wir später sehen werden, haben die eingebauten Enumeratoren von Ruby 1.9 erheblich mehr Funktionalität als diejenige, die von der
enumerator
-Bibliothek von Ruby 1.8 bereitgestellt wird.)
Enumeratoren gehören zur Klasse
Enumerable::Enumerator
. Diese Klasse kann zwar direkt mit
new
instantiiert werden, aber das ist nicht die übliche Art und Weise, wie Enumeratoren erzeugt werden. Verwenden Sie stattdessen
to_enum
oder das Synonym
enum_for
; beide sind Methoden von
Object
. Ohne Argumente gibt
to_enum
einen Enumerator zurück, dessen
each
-Methode einfach die
each
-Methode des Zielobjekts aufruft. Angenommen, Sie haben ein Array und eine Methode, die ein Enumerable-Objekt erwartet. Sie sollten nicht das Array-Objekt selbst übergeben, weil es veränderlich ist und Sie nicht darauf vertrauen sollten, dass die Methode es nicht verändert. Anstatt zur Sicherheit eine komplette Kopie des Array zu erzeugen, rufen Sie einfach seine
to_enum
-Methode auf und übergeben den erhaltenen Enumerator anstelle des Array selbst. Im Prinzip erzeugen Sie ein aufzählbares, aber unveränderliches Proxy-Objekt für Ihr Array:
# Diese Methode mit einem Enumerator statt mit einem
# veränderlichen Array aufrufen. Dies ist eine nützliche defensive
# Strategie, um Fehler zu vermeiden.
process(data.to_enum) # Statt des einfachen process(data)
Sie können auch Argumente an
to_enum
übergeben, wobei das Synonym
enum_for
in diesem Fall natürlicher erscheint. Das erste Argument sollte ein Symbol sein, das eine Iteratormethode identifiziert. Die Methode
each
des erhaltenen
Enumerator
-Objekts ruft die angegebene Methode des Originalobjekts auf. Alle übrigen Argumente für
enum_for
werden an diese genannte Methode übergeben. In Ruby 1.9 ist die Klasse
String
nicht
Enumerable
, aber sie definiert drei Iteratormethoden:
each_char
,
each_byte
und
each_line
. Angenommen, wir möchten eine
Enumerable
-Methode wie etwa
map
verwenden, und sie soll auf dem Iterator
each_char
basieren. Wir erledigen das, indem wir einen Enumerator erzeugen:
s = "hallo"
s.enum_for(:each_char).map {|c| c.succ } # => ["i", "b", "m", "m", "p"]
In Ruby 1.9 ist es normalerweise noch nicht einmal notwendig,
to_enum
oder
enum_for
wie in den vorherigen Beispielen explizit zu verwenden. Das liegt daran, dass die eingebauten Iteratormethoden von Ruby 1.9 (zu denen die numerischen Iteratoren
times
,
upto
,
downto
und
step
gehören, genau wie
each
und verwandte Methoden von
Enumerable
) automatisch einen Enumerator zurückgeben, wenn sie ohne Block aufgerufen werden. Um also einen Array-Enumerator statt des Array selbst an eine Methode zu übergeben, können Sie einfach die Methode
each
aufrufen:
process(data.each_char) # Statt des einfachen process(data)
Diese Syntax ist sogar noch natürlicher, wenn wir den Alias [ 22 ]
chars
anstelle von
each_char
verwenden. Um
Weitere Kostenlose Bücher