it-swarm.com.de

Warum Symbole als Hash-Schlüssel in Ruby verwenden?

Oft benutzen Leute Symbole als Schlüssel in einem Ruby Hash.

Was ist der Vorteil gegenüber einer Zeichenfolge?

Z.B.:

hash[:name]

vs.

hash['name']
153
user979912

TL; DR:

Die Verwendung von Symbolen spart nicht nur Zeit beim Vergleichen, sondern auch Speicher, da sie nur einmal gespeichert werden.

Ruby-Symbole sind unveränderlich (können nicht geändert werden), was das Nachschlagen von Inhalten erleichtert

Kurze (ish) Antwort:

Die Verwendung von Symbolen spart nicht nur Zeit beim Vergleichen, sondern auch Speicher, da sie nur einmal gespeichert werden.

Symbole in Ruby sind im Grunde "unveränderliche Zeichenfolgen" . Das bedeutet, dass sie nicht geändert werden können und dass dasselbe Symbol, wenn Sie im gesamten Quellcode mehrmals darauf verweisen, immer als dieselbe Entität gespeichert wird, z hat die gleiche Objekt-ID.

Strings hingegen sind veränderbar , sie können jederzeit geändert werden. Dies impliziert, dass Ruby jede von Ihnen erwähnte Zeichenfolge in Ihrem gesamten Quellcode in einer separaten Entität speichern muss, z. Wenn Sie einen String "name" haben, der mehrfach in Ihrem Quellcode erwähnt wurde, muss Ruby diese alle in separaten String-Objekten speichern, da sie sich später ändern können (das ist die Natur eines Ruby - Strings). .

Wenn Sie eine Zeichenfolge als Hash-Schlüssel verwenden, muss Ruby die Zeichenfolge auswerten und ihren Inhalt prüfen (und eine Hash-Funktion dazu berechnen) und das Ergebnis mit den (gehashten) Werten der bereits vorhandenen Schlüssel vergleichen im Hash gespeichert.

Wenn Sie ein Symbol als Hash-Schlüssel verwenden, bedeutet dies, dass es unveränderlich ist, sodass Ruby im Grunde genommen nur einen Vergleich der (Hash-) Funktion der) Objekt-ID mit den (Hash-) Objekt-IDs von Schlüsseln durchführen kann, die sind bereits im Hash gespeichert. (viel schneller)

Nachteil: Jedes Symbol belegt einen Platz in der Symboltabelle des Ruby -Interpreters, der niemals freigegeben wird. Symbole werden niemals durch Müll gesammelt. Ein Eckfall liegt also vor, wenn Sie eine große Anzahl von Symbolen haben (z. B. automatisch generierte). In diesem Fall sollten Sie bewerten, wie sich dies auf die Größe Ihres Ruby - Interpreters auswirkt.

Anmerkungen:

Wenn Sie Zeichenfolgenvergleiche durchführen, kann Ruby Symbole nur anhand ihrer Objekt-IDs vergleichen, ohne sie auswerten zu müssen. Das ist viel schneller als das Vergleichen von Strings, die ausgewertet werden müssen.

Wenn Sie auf einen Hash zugreifen, wendet Ruby immer eine Hash-Funktion an, um einen "Hash-Schlüssel" aus dem von Ihnen verwendeten Schlüssel zu berechnen. Sie können sich so etwas wie einen MD5-Hash vorstellen. Und dann vergleicht Ruby diese "gehackten Schlüssel" miteinander.

Lange Antwort:

http://www.reactive.io/tips/2009/01/11/the-difference-between-Ruby-symbols-and-strings

http://www.randomhacks.net/articles/2007/01/20/13-ways-of-looking-at-a-Ruby-symbol

211
Tilo

Der Grund ist die Effizienz mit mehreren Gewinnen gegenüber einer Zeichenfolge:

  1. Die Symbole sind unveränderlich. Die Frage "Was passiert, wenn sich der Schlüssel ändert?" muss nicht gefragt werden.
  2. Zeichenfolgen werden in Ihrem Code dupliziert und beanspruchen normalerweise mehr Speicherplatz.
  3. Hash-Lookups müssen den Hash der Schlüssel berechnen, um sie zu vergleichen. Dies ist O(n) für Strings und eine Konstante für Symbole.

Darüber hinaus wurde in Ruby 1.9 eine vereinfachte Syntax nur für Hashs mit Symboltasten (z. B. h.merge(foo: 42, bar: 6)) eingeführt, und Ruby 2.0 has Schlüsselwortargumente das funktioniert nur für Symbolschlüssel.

Anmerkungen :

1) Es könnte Sie überraschen, zu erfahren, dass Ruby= String Schlüssel anders behandelt als jeder andere Typ.

s = "foo"
h = {}
h[s] = "bar"
s.upcase!
h.rehash   # must be called whenever a key changes!
h[s]   # => nil, not "bar"
h.keys
h.keys.first.upcase!  # => TypeError: can't modify frozen string

Nur für Zeichenfolgenschlüssel verwendet Ruby anstelle des Objekts selbst eine eingefrorene Kopie.

2) Die Buchstaben "b", "a" und "r" werden nur einmal für alle Vorkommen von :bar In einem Programm gespeichert. Vor Ruby 2.2 war es eine schlechte Idee, ständig neue Symbols zu erstellen, die nie wiederverwendet wurden, da sie für immer in der globalen Symbol-Nachschlagetabelle verbleiben würden. Ruby 2.2 wird sie mit Müll sammeln, also keine Sorge.

3) Tatsächlich hat die Berechnung des Hash für ein Symbol in Ruby 1.8.x keine Zeit in Anspruch genommen, da die Objekt-ID direkt verwendet wurde:

:bar.object_id == :bar.hash # => true in Ruby 1.8.7

In Ruby 1.9.x hat sich dies geändert, da sich die Hashes von einer Sitzung zur nächsten ändern (einschließlich der von Symbols):

:bar.hash # => some number that will be different next time Ruby 1.9 is ran
21

Betreff: Was ist der Vorteil gegenüber der Verwendung einer Zeichenfolge?

  • Styling: Es ist der Ruby-Weg
  • (Sehr) etwas schnellere Wertsuchvorgänge, da das Hashing eines Symbols dem Hashing einer Ganzzahl und dem Hashing einer Zeichenfolge entspricht.

  • Nachteil: Verbraucht einen Platz in der Symboltabelle des Programms, der niemals freigegeben wird.

7
Larry K

Ich wäre sehr an einer Nachverfolgung von eingefrorenen Zeichenfolgen interessiert, die in Ruby 2.x eingeführt wurden.

Wenn Sie mit zahlreichen Zeichenfolgen arbeiten, die von einer Texteingabe stammen (ich denke an HTTP-Parameter oder Payload, zum Beispiel über Rack), ist es viel einfacher, Zeichenfolgen überall zu verwenden.

Wenn Sie mit Dutzenden von ihnen zu tun haben, diese sich aber nie ändern (wenn sie Ihr geschäftliches "Vokabular" sind), denke ich gern, dass das Einfrieren von ihnen einen Unterschied machen kann. Ich habe noch keinen Benchmark durchgeführt, aber ich denke, es würde der Leistung der Symbole nahe kommen.

0
jlecour