Obwohl ich " Ruby-Symbole verstehen " gelesen habe , bin ich immer noch verwirrt über die Darstellung der Daten im Speicher, wenn es um die Verwendung von Symbolen geht. Wenn ein Symbol, von denen zwei in verschiedenen Objekten enthalten sind, am selben Speicherort vorhanden ist, wie kommt es dann, dass sie unterschiedliche Werte enthalten ? Ich hätte erwartet, dass derselbe Speicherort den gleichen Wert enthält.
Dies ist ein Zitat aus dem Link:
Im Gegensatz zu Zeichenfolgen werden gleichnamige Symbole initialisiert und existieren während einer Ruby-Sitzung nur einmal im Speicher
Ich verstehe nicht, wie es gelingt, die im selben Speicherort enthaltenen Werte zu unterscheiden.
Betrachten Sie dieses Beispiel:
patient1 = { :ruby => "red" }
patient2 = { :ruby => "programming" }
patient1.each_key {|key| puts key.object_id.to_s}
3918094
patient2.each_key {|key| puts key.object_id.to_s}
3918094
patient1
und patient2
sind beide Hashes, das ist in Ordnung. :ruby
ist jedoch ein Symbol. Wenn wir Folgendes ausgeben würden:
patient1.each_key {|key| puts key.to_s}
Was wird dann ausgegeben? "red"
oder "programming"
?
Ich vergesse Hashes für eine Sekunde und denke, ein Symbol ist ein Zeiger auf einen Wert. Die Fragen, die ich habe, sind:
- Kann ich einem Symbol einen Wert zuweisen?
- Ist ein Symbol nur ein Zeiger auf eine Variable mit einem Wert darin?
- Wenn Symbole global sind, bedeutet das, dass ein Symbol immer auf eine Sache verweist?
puts patient1[:ruby]
, wird "rot" gedruckt, wenn Sie sagenputs patient2[:ruby]
, wird "Programmierung" gedruckt.Antworten:
Bedenken Sie:
Wenn Sie also ein Symbolobjekt erstellen, verweist es, solange sein Inhalt identisch ist, auf dasselbe Objekt im Speicher. Dies ist kein Problem, da ein Symbol ein unveränderliches Objekt ist . Saiten sind veränderlich.
(Als Antwort auf den Kommentar unten)
Im Originalartikel wird der Wert nicht in einem Symbol gespeichert, sondern in einem Hash. Bedenken Sie:
Dadurch werden sechs Objekte im Speicher erstellt - vier Zeichenfolgenobjekte und zwei Hashobjekte.
Dadurch werden nur fünf Objekte im Speicher erstellt - ein Symbol, zwei Zeichenfolgen und zwei Hash-Objekte.
quelle
Hash
(erstellt von {... => ...} in Ihrem Code), das Schlüssel / Wert-Paare speichert, nicht dasSymbol
s selbst. DieSymbol
s (zB:symbol
oder oder:sym
oder:ruby
) sind die Schlüssel in den Paaren. Nur als Teil vonHash
"zeigen" sie auf irgendetwas.Ich konnte Symbole erkennen, wenn ich so darüber nachdachte. Eine Ruby-Zeichenfolge ist ein Objekt mit einer Reihe von Methoden und Eigenschaften. Leute verwenden gerne Zeichenfolgen für Schlüssel, und wenn die Zeichenfolge für einen Schlüssel verwendet wird, werden all diese zusätzlichen Methoden nicht verwendet. Also machten sie Symbole, bei denen es sich um Zeichenfolgenobjekte handelt, bei denen alle Funktionen entfernt wurden, mit Ausnahme derjenigen, die für einen guten Schlüssel erforderlich sind.
Stellen Sie sich Symbole als konstante Zeichenfolgen vor.
quelle
Das Symbol
:ruby
enthält kein"red"
oder"programming"
. Das Symbol:ruby
ist nur das Symbol:ruby
. Es sind Ihre Hashes,patient1
undpatient2
jeder enthält diese Werte, auf die jeweils mit demselben Schlüssel verwiesen wird.Stellen Sie sich das so vor: Wenn Sie am Weihnachtsmorgen ins Wohnzimmer gehen und zwei Kisten mit einem Etikett sehen, auf denen "Kezzer" steht. On hat Socken drin und der andere hat Kohle. Sie werden nicht verwirrt sein und fragen, wie "Kezzer" sowohl Socken als auch Kohle enthalten kann, obwohl es der gleiche Name ist. Weil der Name die (beschissenen) Geschenke nicht enthält. Es zeigt nur auf sie. Enthält in ähnlicher Weise
:ruby
nicht die Werte in Ihrem Hash, sondern zeigt nur auf sie.quelle
mystring = :steveT
das Symbol auf nichts zeigt. Einem Schlüssel in einem Hash ist ein Wert zugeordnet, und der Schlüssel kann ein Symbol sein. Aber ein Symbol muss nicht in einem Hash stehen.Sie können davon ausgehen, dass die von Ihnen abgegebene Erklärung den Wert eines Symbols als etwas anderes definiert als das, was es ist. Tatsächlich ist ein Symbol nur ein "internalisierter" String-Wert, der konstant bleibt. Da sie unter Verwendung einer einfachen Ganzzahlkennung gespeichert werden, werden sie häufig verwendet, da dies effizienter ist als die Verwaltung einer großen Anzahl von Zeichenfolgen variabler Länge.
Nehmen Sie den Fall Ihres Beispiels:
Dies sollte wie folgt gelesen werden: "Deklarieren Sie eine Variable patient1 und definieren Sie sie als Hash. Speichern Sie in diesem den Wert 'rot' unter dem Schlüssel (Symbol 'ruby')."
Eine andere Art, dies zu schreiben, ist:
Während Sie eine Aufgabe ausführen, ist es nicht verwunderlich, dass das Ergebnis, das Sie zurückerhalten, mit dem identisch ist, mit dem Sie es ursprünglich zugewiesen haben.
Das Symbolkonzept kann etwas verwirrend sein, da es in den meisten anderen Sprachen nicht enthalten ist.
Jedes String-Objekt ist unterschiedlich, auch wenn die Werte identisch sind:
Jedes Symbol mit demselben Wert bezieht sich auf dasselbe Objekt:
Durch das Konvertieren von Zeichenfolgen in Symbole werden identische Werte demselben eindeutigen Symbol zugeordnet:
Ebenso wird beim Konvertieren von Symbol zu Zeichenfolge jedes Mal eine eindeutige Zeichenfolge erstellt:
Sie können sich Symbolwerte als aus einer internen Hash-Tabelle gezogen vorstellen und alle Werte anzeigen, die mit einem einfachen Methodenaufruf in Symbole codiert wurden:
Wenn Sie neue Symbole entweder durch die Doppelpunktnotation oder mit .to_sym definieren, wächst diese Tabelle.
quelle
Symbole sind keine Zeiger. Sie enthalten keine Werte. Symbole einfach sind .
:ruby
ist das Symbol:ruby
und das ist alles was dazu gehört. Es gibt keinen Wert enthalten, es nicht tun alles, es existiert nur als Symbol:ruby
. Das Symbol:ruby
ist genau wie die Zahl 1 ein Wert. Es zeigt nicht mehr auf einen anderen Wert als die Zahl 1.quelle
Es wird auch nicht "Ruby" ausgegeben.
Sie verwirren Symbole und Hashes. Sie sind nicht verwandt, aber sie sind zusammen nützlich. Das fragliche Symbol ist
:ruby
; Es hat nichts mit den Werten im Hash zu tun, und die interne Ganzzahldarstellung ist immer dieselbe, und der "Wert" (wenn er in eine Zeichenfolge konvertiert wird) ist immer "rubin".quelle
Zusamenfassend
Symbole lösen das Problem der Erstellung von lesbaren, unveränderlichen Darstellungen, die für die Laufzeit einfacher zu suchen sind als Zeichenfolgen. Stellen Sie sich das wie einen Namen oder ein Etikett vor, das wiederverwendet werden kann.
Warum: Rot ist besser als "Rot"
In dynamischen objektorientierten Sprachen erstellen Sie komplexe, verschachtelte Datenstrukturen mit lesbaren Referenzen. Der Hash ist ein häufiger Anwendungsfall, bei dem Sie Werte eindeutigen Schlüsseln zuordnen - zumindest für jede Instanz eindeutig. Sie können nicht mehr als einen "roten" Schlüssel pro Hash haben.
Es wäre jedoch prozessoreffizienter, einen numerischen Index anstelle von Zeichenfolgenschlüsseln zu verwenden. So wurden Symbole als Kompromiss zwischen Geschwindigkeit und Lesbarkeit eingeführt. Symbole werden viel einfacher aufgelöst als die entsprechende Zeichenfolge. Durch die menschliche Lesbarkeit und die einfache Auflösung von Symbolen zur Laufzeit sind Symbole eine ideale Ergänzung zu einer dynamischen Sprache.
Leistungen
Da Symbole unveränderlich sind, können sie zur Laufzeit gemeinsam genutzt werden. Wenn zwei Hash-Instanzen einen gemeinsamen lexikografischen oder semantischen Bedarf für ein rotes Element haben, würde das Symbol: Rot ungefähr die Hälfte des Speichers verbrauchen, den die Zeichenfolge "rot" für zwei Hashes benötigt hätte.
Da: rot immer wieder an dieselbe Stelle im Speicher aufgelöst wird, kann es über hundert Hash-Instanzen hinweg fast ohne Speichererhöhung wiederverwendet werden, während die Verwendung von "rot" Speicherkosten verursacht, da jede Hash-Instanz die veränderbare Zeichenfolge speichern müsste Schaffung.
Nicht sicher, wie Ruby tatsächlich Symbole / Zeichenfolgen implementiert, aber ein Symbol bietet eindeutig weniger Implementierungsaufwand zur Laufzeit, da es sich um eine feste Darstellung handelt. Plus-Symbole benötigen ein Zeichen weniger als eine Zeichenfolge in Anführungszeichen, und weniger Eingabe ist das ewige Streben nach echten Rubyisten.
Zusammenfassung
Mit einem Symbol wie: rot erhalten Sie die Lesbarkeit der Zeichenfolgendarstellung mit weniger Aufwand aufgrund der Kosten für Zeichenfolgenvergleichsoperationen und der Notwendigkeit, jede Zeichenfolgeninstanz im Speicher zu speichern.
quelle
Ich würde empfehlen, den Wikipedia-Artikel über Hash-Tabellen zu lesen - ich denke, es wird Ihnen helfen, ein Gefühl dafür zu bekommen, was
{:ruby => "red"}
wirklich bedeutet.Eine weitere Übung, die Ihnen helfen könnte, die Situation zu verstehen: Überlegen Sie
{1 => "red"}
. Semantisch bedeutet dies nicht "setze den Wert von1
auf"red"
", was in Ruby unmöglich ist. Es bedeutet vielmehr "ein Hash- Objekt erstellen und den Wert"red"
für den Schlüssel speichern"1
.quelle
Natürlich auch nicht. Die Ausgabe wird sein
ruby
. Übrigens, Sie hätten es in kürzerer Zeit herausfinden können, als Sie für die Eingabe der Frage benötigt haben, indem Sie sie stattdessen einfach in IRB eingegeben haben.Warum sollte es sein
red
oderprogramming
? Symbole bewerten sich immer selbst. Der Wert des Symbols:ruby
ist das Symbol:ruby
selbst und die Zeichenfolgendarstellung des Symbols:ruby
ist der Zeichenfolgenwert"ruby"
.[Übrigens:
puts
konvertiert seine Argumente sowieso immer in Strings. Es besteht keine Notwendigkeit,to_s
darauf zurückzugreifen.]quelle
Ich bin neu bei Ruby, aber ich denke (hoffe?), Dass dies eine einfache Möglichkeit ist, es zu betrachten ...
Ein Symbol ist keine Variable oder Konstante. Es steht nicht für einen Wert oder zeigt auf ihn. Ein Symbol ist ein Wert.
Alles, was es ist, ist eine Zeichenfolge ohne den Objekt-Overhead. Der Text und nur der Text.
Also das:
Ist das gleiche wie das:
Außer Sie können zum Beispiel nicht tun: hellobuddy.upcase. Es ist der String-Wert und NUR der String-Wert.
Ebenso dies:
Ist das gleiche wie das:
Aber auch ohne den Overhead des String-Objekts.
quelle
Eine einfache Möglichkeit, Ihren Kopf darum zu wickeln, besteht darin, zu denken: "Was wäre, wenn ich eine Zeichenfolge anstelle eines Symbols verwenden würde?
Es ist überhaupt nicht verwirrend, oder? Sie verwenden "Ruby" als Schlüssel in einem Hash .
"ruby"
ist ein String-Literal, das ist also der Wert. Die Speicheradresse oder der Zeiger steht Ihnen nicht zur Verfügung. Jedes Mal"ruby"
, wenn Sie aufrufen , erstellen Sie eine neue Instanz davon, dh eine neue Speicherzelle mit demselben Wert -"ruby"
.Der Hash geht dann : „Was ist mein Schlüsselwert? Oh , es ist
"ruby"
. Dann ordnet diesen Wert auf‚rot‘oder‚Programmierung‘. Mit anderen Worten,:ruby
nicht dereferenzieren nicht"red"
oder"programming"
. Die Hash - Karten:ruby
auf"red"
oder"programming"
.Vergleichen Sie das damit, wenn wir Symbole verwenden
Der Wert von
:ruby
ist auch"ruby"
effektiv.Warum? Weil Symbole im Wesentlichen Zeichenfolgenkonstanten sind . Konstanten haben nicht mehrere Instanzen. Es ist die gleiche Speicheradresse. Und eine Speicheradresse hat einen bestimmten Wert, sobald sie dereferenziert ist. Bei Symbolen ist der Zeigername das Symbol, und der dereferenzierte Wert ist eine Zeichenfolge, die in diesem Fall mit dem Symbolnamen übereinstimmt
"ruby"
.In einem Hash verwenden Sie nicht das Symbol, den Zeiger, sondern den verzögerten Wert. Du benutzt nicht
:ruby
, aber"ruby"
. Der Hash sucht dann nach Schlüssel"ruby"
, der Wert ist"red"
oder"programming"
, je nachdem, wie Sie den Hash definiert haben.Das Paradigmenwechsel- und Take-Home-Konzept besteht darin, dass der Wert eines Symbols ein völlig anderes Konzept ist als ein Wert, der durch einen Hash zugeordnet wird, wenn ein Schlüssel für diesen Hash angegeben wird.
quelle