Wenn mein Skript mindestens zwei Instanzen derselben Zeichenfolge enthält, sollte ich stattdessen ein Symbol verwenden?
Wenn mein Skript mindestens zwei Instanzen derselben Zeichenfolge enthält, sollte ich stattdessen ein Symbol verwenden?
Antworten:
Eine einfache Faustregel lautet, jedes Mal Symbole zu verwenden, wenn Sie interne Bezeichner benötigen. Verwenden Sie für Ruby <2.2 Symbole nur, wenn sie nicht dynamisch generiert werden, um Speicherverluste zu vermeiden.
Der einzige Grund, sie nicht für Bezeichner zu verwenden, die dynamisch generiert werden, sind Speicherprobleme.
Diese Frage ist sehr häufig, da viele Programmiersprachen keine Symbole haben, sondern nur Zeichenfolgen, und daher werden Zeichenfolgen auch als Bezeichner in Ihrem Code verwendet. Sie sollten sich Gedanken darüber machen, was Symbole sein sollen , nicht nur, wenn Sie Symbole verwenden sollten . Symbole sollen Bezeichner sein. Wenn Sie dieser Philosophie folgen, besteht die Möglichkeit, dass Sie die Dinge richtig machen.
Es gibt verschiedene Unterschiede zwischen der Implementierung von Symbolen und Zeichenfolgen. Das Wichtigste an Symbolen ist, dass sie unveränderlich sind . Dies bedeutet, dass sich ihr Wert niemals ändern wird. Aus diesem Grund werden Symbole schneller instanziiert als Zeichenfolgen, und einige Operationen wie das Vergleichen zweier Symbole sind ebenfalls schneller.
Die Tatsache, dass ein Symbol unveränderlich ist, ermöglicht es Ruby, jedes Mal, wenn Sie auf das Symbol verweisen, dasselbe Objekt zu verwenden, wodurch Speicherplatz gespart wird. Jedes Mal, wenn der Interpreter liest :my_key
, kann er es aus dem Speicher entnehmen, anstatt es erneut zu instanziieren. Dies ist kostengünstiger als jedes Mal eine neue Zeichenfolge zu initialisieren.
Sie können eine Liste aller Symbole abrufen, die bereits mit dem Befehl instanziiert wurden Symbol.all_symbols
:
symbols_count = Symbol.all_symbols.count # all_symbols is an array with all
# instantiated symbols.
a = :one
puts a.object_id
# prints 167778
a = :two
puts a.object_id
# prints 167858
a = :one
puts a.object_id
# prints 167778 again - the same object_id from the first time!
puts Symbol.all_symbols.count - symbols_count
# prints 2, the two objects we created.
Bei Ruby-Versionen vor 2.2 ist dieser Speicher nach der Instanziierung eines Symbols nie wieder frei . Die einzige Möglichkeit, den Speicher freizugeben, besteht darin, die Anwendung neu zu starten. Symbole sind daher auch eine Hauptursache für Speicherverluste, wenn sie falsch verwendet werden. Der einfachste Weg, einen Speicherverlust zu erzeugen, ist die Verwendung der Methode to_sym
für Benutzereingabedaten, da sich diese Daten immer ändern und ein neuer Teil des Speichers für immer in der Softwareinstanz verwendet wird. Ruby 2.2 hat den Symbol-Garbage-Collector eingeführt , der dynamisch generierte Symbole freigibt, sodass die durch dynamisches Erstellen von Symbolen erzeugten Speicherlecks kein Problem mehr darstellen.
Beantwortung Ihrer Frage:
Stimmt es, dass ich anstelle einer Zeichenfolge ein Symbol verwenden muss, wenn meine Anwendung oder mein Skript mindestens zwei gleiche Zeichenfolgen enthält?
Wenn Sie nach einer Kennung suchen, die intern in Ihrem Code verwendet werden soll, sollten Sie Symbole verwenden. Wenn Sie eine Ausgabe drucken, sollten Sie Zeichenfolgen verwenden, auch wenn diese mehrmals angezeigt werden, und sogar zwei verschiedene Objekte im Speicher zuweisen.
Hier ist die Begründung:
@AlanDert: Wenn ich im haml-Code mehrmals etwas wie% input {type :: checkbox} verwende, was soll ich dann als Kontrollkästchen verwenden?
Ich schon.
@AlanDert: Aber um ein Symbol auf einer HTML-Seite auszudrucken, sollte es in einen String konvertiert werden, nicht wahr? Was bringt es dann, es zu benutzen?
Was ist die Art einer Eingabe? Eine Kennung der Art der Eingabe, die Sie verwenden möchten, oder etwas, das Sie dem Benutzer anzeigen möchten?
Es ist wahr, dass es irgendwann zu HTML-Code wird, aber im Moment, in dem Sie diese Zeile Ihres Codes schreiben, ist es gemeint, ein Bezeichner zu sein - es gibt an, welche Art von Eingabefeld Sie benötigen. Daher wird es in Ihrem Code immer wieder verwendet und hat immer die gleiche "Zeichenfolge" wie der Bezeichner und erzeugt keinen Speicherverlust.
Warum werten wir die Daten nicht aus, um festzustellen, ob die Zeichenfolgen schneller sind?
Dies ist ein einfacher Benchmark, den ich dafür erstellt habe:
require 'benchmark'
require 'haml'
str = Benchmark.measure do
10_000.times do
Haml::Engine.new('%input{type: "checkbox"}').render
end
end.total
sym = Benchmark.measure do
10_000.times do
Haml::Engine.new('%input{type: :checkbox}').render
end
end.total
puts "String: " + str.to_s
puts "Symbol: " + sym.to_s
Drei Ausgänge:
# first time
String: 5.14
Symbol: 5.07
#second
String: 5.29
Symbol: 5.050000000000001
#third
String: 4.7700000000000005
Symbol: 4.68
Die Verwendung von Smbols ist also etwas schneller als die Verwendung von Strings. Warum ist das so? Dies hängt davon ab, wie HAML implementiert ist. Ich müsste ein bisschen HAML-Code hacken, um zu sehen, aber wenn Sie weiterhin Symbole im Konzept eines Bezeichners verwenden, wird Ihre Anwendung schneller und zuverlässiger. Wenn Fragen auftauchen, vergleichen Sie sie und erhalten Sie Ihre Antworten.
Einfach ausgedrückt ist ein Symbol ein Name, der aus Zeichen besteht, aber unveränderlich ist. Eine Zeichenfolge ist dagegen ein geordneter Container für Zeichen, deren Inhalt sich ändern darf.
Um zwei Zeichenfolgen zu vergleichen, müssen wir möglicherweise jedes Zeichen betrachten. Für zwei Zeichenfolgen der Länge N sind N + 1-Vergleiche erforderlich (die von Informatikern als "O (N) -Zeit" bezeichnet werden).
def string_comp str1, str2
return false if str1.length != str2.length
for i in 0...str1.length
return false if str1[i] != str2[i]
end
return true
end
string_comp "foo", "foo"
Da sich jedes Erscheinungsbild von: foo auf dasselbe Objekt bezieht, können wir Symbole vergleichen, indem wir uns die Objekt-IDs ansehen. Wir können dies mit einem einzigen Vergleich tun (den Informatiker als "O (1) -Zeit" bezeichnen).
def symbol_comp sym1, sym2
sym1.object_id == sym2.object_id
end
symbol_comp :foo, :foo
In C ++ können wir "Aufzählungen" verwenden, um Familien verwandter Konstanten darzustellen:
enum BugStatus { OPEN, CLOSED };
BugStatus original_status = OPEN;
BugStatus current_status = CLOSED;
Da Ruby eine dynamische Sprache ist, müssen wir uns nicht darum kümmern, einen BugStatus-Typ zu deklarieren oder die gesetzlichen Werte zu verfolgen. Stattdessen stellen wir die Aufzählungswerte als Symbole dar:
original_status = :open
current_status = :closed
3. Ein Rubinsymbol ist ein konstanter, eindeutiger Name
In Ruby können wir den Inhalt einer Zeichenfolge ändern:
"foo"[0] = ?b # "boo"
Wir können den Inhalt eines Symbols jedoch nicht ändern:
:foo[0] = ?b # Raises an error
Wenn Sie Schlüsselwortargumente an eine Ruby-Funktion übergeben, geben Sie die Schlüsselwörter mithilfe von Symbolen an:
# Build a URL for 'bug' using Rails.
url_for :controller => 'bug',
:action => 'show',
:id => bug.id
In der Regel verwenden wir Symbole, um die Schlüssel einer Hash-Tabelle darzustellen:
options = {}
options[:auto_save] = true
options[:show_comments] = false
Hier ist ein schöner Benchmark für Zeichenfolgen und Symbole, den ich an der Codecademy gefunden habe:
require 'benchmark'
string_AZ = Hash[("a".."z").to_a.zip((1..26).to_a)]
symbol_AZ = Hash[(:a..:z).to_a.zip((1..26).to_a)]
string_time = Benchmark.realtime do
1000_000.times { string_AZ["r"] }
end
symbol_time = Benchmark.realtime do
1000_000.times { symbol_AZ[:r] }
end
puts "String time: #{string_time} seconds."
puts "Symbol time: #{symbol_time} seconds."
Die Ausgabe ist:
String time: 0.21983 seconds.
Symbol time: 0.087873 seconds.
Verwenden Sie Symbole als Hash-Schlüssel-IDs
{key: "value"}
Mit Symbolen können Sie die Methode in einer anderen Reihenfolge aufrufen
def write (file:, data:, mode: "ascii") # der Kürze halber entfernt Ende Schreiben (Daten: 123, Datei: "test.txt")
einfrieren, um als Zeichenfolge zu behalten und Speicherplatz zu sparen
label = 'My Label'.freeze
/
(nachstrings
) aus dem Link entfernen . Hier ist es: www.reactive.io/tips/2009/01/11/the-difference-between-ruby- Symbole-und-Zeichenfolgen