Die Programmiersprache Ruby (German Edition)
1.8-Interpreter ausgeführt wird, können Sie
proc
getrost als eleganteres Kürzel für
Proc.new
verwenden.
6.5.1.4 Lambda-Literale
Ruby 1.9 unterstützt eine völlig neue Syntax zur Definition von Lambdas als Literalen. Wir beginnen mit einem Ruby 1.8-Lambda, das mithilfe der Methode
lambda
erstellt wird:
succ = lambda {|x| x+1}
In Ruby 1.9 können Sie diese wie folgt in ein Literal konvertieren:
Ersetzen Sie den Methodennamen
lambda
durch die Satzzeichenfolge
->
.
Verschieben Sie die Liste der Argumente aus den geschweiften Klammern heraus, unmittelbar vor diese.
Ändern Sie die Begrenzungen der Argumentliste von
||
in
()
.
Mithilfe dieser Änderungen erhalten wir ein Ruby 1.9-Lambda-Literal:
succ = ->(x){ x+1 }
succ
enthält nun ein
Proc
-Objekt, das wir genauso verwenden können wie jedes andere:
succ.call(2) # => 3
Die Einführung dieser Syntax in Ruby wurde kontrovers diskutiert, und sie ist etwas gewöhnungsbedürftig. Beachten Sie dass die Pfeilzeichen
->
sich von denjenigen unterscheiden, die in Hash-Literalen verwendet werden. Ein Lambda-Literal verwendet einen Pfeil, der mit einem Bindestrich geschrieben wird, während ein Hash-Literal einen Pfeil mit einem Gleichheitszeichen verwendet.
Genau wie bei Blöcken in Ruby 1.9 kann die Argumentliste eines Lambda-Literals die Deklaration blocklokaler Variablen enthalten, die garantiert keine gleichnamigen Variablen im umgebenden Gültigkeitsbereich überschreiben. Setzen Sie einfach ein Semikolon und eine Liste lokaler Variablen hinter die Parameterliste:
# Dieses Lambda hat zwei Argumente und deklariert drei lokale Variablen.
f = ->(x,y; i,j,k) { ... }
Ein Vorteil dieser neuen Lambda-Syntax gegenüber den traditionellen, blockbasierten Lambda-Erzeugungsmethoden besteht darin, dass die Ruby 1.9-Syntax die Deklaration von Lambdas mit Argumentstandardwerten erlaubt, genau wie bei Methoden:
zoom = ->(x,y,factor=2) { [x*factor, y*factor] }
Wie bei Methodendeklarationen sind die Klammern in Lambda-Literalen optional, weil die Parameterliste und die Liste der lokalen Variablen hinreichend durch
->
,
;
und
{
begrenzt werden. Wir könnten die drei Lambdas von oben wie folgt neu schreiben:
succ = ->x { x+1 }
f = -> x,y; i,j,k { ... }
zoom = ->x,y,factor=2 { [x*factor, y*factor] }
Parameter und lokale Variablen sind in Lambdas natürlich optional, und ein Lambda-Literal kann sie komplett weglassen. Das minimale Lambda, das keine Argumente entgegennimmt und
nil
zurückgibt, sieht folgendermaßen aus:
->{}
Ein Vorteil dieser neuen Syntax ist ihre Kürze. Sie kann nützlich sein, wenn Sie ein Lambda als Argument an eine Methode oder ein anderes Lambda übergeben möchten:
def compose(f,g) # Zwei Lambdas zusammensetzen
->(x) { f.call(g.call(x)) }
end
succOfSquare = compose(->x{x+1}, ->x{x*x})
succOfSquare.call(4) # => 17: Berechnet (4*4)+1
Lambda-Literale erzeugen
Proc
-Objekte und sind nicht dasselbe wie Blöcke. Wenn Sie ein Lambda-Literal an eine Methode übergeben möchten, die einen Block erwartet, stellen Sie dem Literal ein
&
voran, genau wie bei jedem anderen
Proc
-Objekt. Hier sehen Sie, wie Sie ein Array von Zahlen in absteigender Reihenfolge sortieren könnten, sowohl mit einem Block als auch mit einem Lambda-Literal:
data.sort {|a,b| b-a } # Die Block-Version
data.sort &->(a,b){ b-a } # Die Lambda-Literal-Version
In diesem Fall ist die gewöhnliche Blocksyntax einfacher, wie Sie sehen.
6.5.2 Procs und Lambdas aufrufen
Procs und Lambdas sind Objekte, keine Methoden, und sie können nicht auf dieselbe Weise aufgerufen werden wie Methoden. Wenn
p
auf ein
Proc
-Objekt verweist, können Sie
p
nicht als Methode aufrufen. Aber da
p
ein Objekt ist, können Sie eine Methode von
p
aufrufen. Wir haben bereits erwähnt, dass die Klasse
Proc
eine Methode namens
call
definiert. Ein Aufruf dieser Methode führt den Code im ursprünglichen Block aus. Die Argumente, die Sie der Methode
call
übergeben, werden zu Argumenten des Blocks, und der Rückgabewert des Blocks wird zum Rückgabewert der Methode
call
:
f = Proc.new {|x,y| 1.0/(1.0/x + 1.0/y) }
z = f.call(x,y)
Die Klasse
Proc
definiert auch den Array-Zugriffsoperator so, dass er genauso funktioniert wie
call
. Das bedeutet, dass Sie eine Proc oder ein Lambda mithilfe einer Syntax ansprechen können, die wie ein Methodenaufruf aussieht, in dem runde durch eckige Klammern ersetzt werden. Der obige
Proc
-Aufrufcode könnte beispielsweise durch folgenden Code ersetzt werden:
z = f[x,y]
Ruby 1.9 bietet eine
Weitere Kostenlose Bücher