Was sind die Unterschiede zwischen Hashes wie diese und Lambdas?
Lambdas und Hashes haben nichts gemeinsam. Deine Frage ist wie zu fragen:
Was sind die Unterschiede zwischen Methoden und Arrays?
Es ist einfach so, dass Hashes einen Standardwert für einen nicht existierenden Schlüssel angeben können:
h = Hash.new(10)
h["a"] = 2
puts h["a"]
puts h["b"]
--output:--
2
10
Hashes bieten auch eine Möglichkeit, den Standardwert dynamisch festzulegen: Du kannst einen Block angeben. Hier ist ein Beispiel:
h = Hash.new do |h, key|
h[key] = key.length
end
puts h['hello']
puts h['hi']
p h
--output:--
5
2
{"hello"=>5, "hi"=>2}
Wenn du auf einen nicht existierenden Schlüssel zugreifst, wird der Block aufgerufen und der Block kann tun, was auch immer du willst. Also hat jemand clever herausgefunden, dass du eine Hash erstellen und einen Standardwert angeben kannst, der Fibonacci-Zahlen berechnet. So funktioniert es:
h = Hash.new do |h, key|
if key < 2
h[key] = key
else
h[key] = h[key-1] + h[key-2]
end
end
Das erstellt die Hash h, die eine Hash ohne Schlüssel oder Werte ist. Wenn du dann schreibst:
puts h[3]
...ist 3 ein nicht existierender Schlüssel, also wird der Block mit den Argumenten h und 3 aufgerufen. Der else-Zweig im Block wird ausgeführt, was dir gibt:
h[3-1] + h[3-2]
oder:
h[2] + h[1]
Aber um diese Aussage zu bewerten, muss Ruby zuerst h[2] bewerten. Aber wenn Ruby h[2] in der Hash nachschlägt, ist der Schlüssel 2 nicht existent, also wird der Block mit den Argumenten h und 2 aufgerufen, der dir gibt:
(h[2-1] + h[2-2]) + h[1]
oder:
(h[1] + h[0]) + h[1]
Um diese Aussage zu bewerten, muss Ruby zuerst das erste h[1] bewerten und wenn Ruby versucht, h[1] in der Hash nachzuschlagen, ist 1 ein nicht existierender Schlüssel, also wird der Block mit den Argumenten h und 1 aufgerufen. Diesmal wird der if-Zweig ausgeführt, wodurch dies passiert:
h[1] = 1
und 1 wird als Wert von h[1] zurückgegeben, was dir dies gibt:
(1 + h[0]) + h[1]
Dann sucht Ruby h[0] nach und weil 0 ein nicht existierender Schlüssel ist, wird der Block mit den Argumenten h und 0 aufgerufen und der if-Zweig wird ausgeführt und führt dies aus:
h[0] = 0
und 0 wird als Wert von h[0] zurückgegeben, was dir dies gibt:
(1 + 0) + h[1]
Dann sucht Ruby h[1] in der Hash und dieses Mal existiert der Schlüssel 1 und hat den Wert 1, was dir gibt:
(1 + 0) + 1
Und das ergibt 2, also wird h[3] gleich 2 gesetzt. Nachdem h[3] aufgerufen wurde, erhältst du diese Ausgabe:
puts h[3]
p h
--output:--
2
{1=>1, 0=>0, 2=>1, 3=>2}
Wie du sehen kannst, sind die vorherigen Berechnungen alle im Hash zwischengespeichert, was bedeutet, dass diese Berechnungen nicht erneut für andere Fibonacci-Zahlen durchgeführt werden müssen.