Was ist der Doppelpunktoperator in Ruby?

234

Wenn ich sage { :bla => 1, :bloop => 2 }, was genau macht das :? Ich habe irgendwo darüber gelesen, wie ähnlich es einer Zeichenfolge ist, aber irgendwie ein Symbol.

Ich bin nicht ganz klar über das Konzept, könnte mich jemand aufklären?

Luxusmodus
quelle
1
mögliches Duplikat des Verstehens von Symbolen in Ruby
Mladen Jablanović
7
Schauen Sie sich das an: Der Ruby_Newbie Leitfaden zu Symbolen
Hengjie
Dieses Video zeigt Ihnen alles, was Sie über Symbole wissen müssen.
Totymedli

Antworten:

249

:fooist ein Symbol namens "foo". Symbole haben die Besonderheit, dass zwei beliebige gleichnamige Symbole identisch sind:

"foo".equal? "foo"  # false
:foo.equal? :foo    # true

Dies macht das Vergleichen von zwei Symbolen sehr schnell (da nur ein Zeigervergleich erforderlich ist, im Gegensatz zum Vergleichen aller Zeichen wie in einer Zeichenfolge), und Sie haben nicht zig Kopien desselben Symbols im Umlauf.

Im Gegensatz zu Zeichenfolgen sind Symbole auch unveränderlich.

Chris Jester-Young
quelle
2
Ich frage mich nur, warum der Literal-String das String-Interning nicht unterstützt.
onmyway133
5
@ onmyway133 Weil Rubys Strings veränderlich sind. Internierung gilt nur für unveränderliche Werte.
Chris Jester-Young
3
a) Warum ist "foo".equal? "foo"falsch? b) Können Sie sich irgendwo auf ein Symbol beziehen und es im Wesentlichen wie globale Variablen machen?
Arc676
2
@ Arc676 1. führt equal?in Ruby einen Identitätsvergleich durch. Jedes String-Literal erstellt wie "foo"eine neue String-Instanz. Dies funktioniert auf diese Weise, da Zeichenfolgen in Ruby veränderbar sind. 2. Symbole sind global, ähneln jedoch eher globalen Konstanten als globalen Variablen, da Symbole keinen Status haben. Die Verwendung von Symbolen ist daher kein Antimuster wie globale Variablen.
Chris Jester-Young
2
@ Arc676 "foo" == "foo"# => true
Filip Bartuzi
44

Nur um einige der in den Antworten genannten Dinge zu demonstrieren:

require 'benchmark'

n = 1_000_000

print '"foo".equal? "foo" -> ', ("foo".equal? "foo"), "\n"
print '"foo" == "foo"     -> ', ("foo" == "foo"    ), "\n"
print ':foo.equal? :foo   -> ', (:foo.equal? :foo  ), "\n"
print ':foo == :foo       -> ', (:foo == :foo      ), "\n"

Benchmark.bm(10) do |b|
  b.report('string')     { n.times { "foo".equal? "foo" }}
  b.report('str == str') { n.times { "foo" == "foo"     }}
  b.report('symbol')     { n.times { :foo.equal? :foo   }}
  b.report('sym == sym') { n.times { :foo == :foo       }}
end

Beim Ausführen werden folgende Ausgaben ausgeführt:

"foo".equal? "foo" -> false
"foo" == "foo"     -> true
:foo.equal? :foo   -> true
:foo == :foo       -> true

Der Vergleich einer Zeichenfolge mit einer Zeichenfolge unter Verwendung equal?schlägt fehl, da es sich um unterschiedliche Objekte handelt, auch wenn sie den gleichen Inhalt haben. ==vergleicht den Inhalt und die entsprechenden Überprüfungen mit Symbolen sind viel schneller.

                 user     system      total        real
string       0.370000   0.000000   0.370000 (  0.371700)
str == str   0.330000   0.000000   0.330000 (  0.326368)
symbol       0.170000   0.000000   0.170000 (  0.174641)
sym == sym   0.180000   0.000000   0.180000 (  0.179374)

Beide Symboltests sind grundsätzlich hinsichtlich der Geschwindigkeit gleich. Nach 1.000.000 Iterationen gibt es nur einen Unterschied von 0,004733 Sekunden. Ich würde also sagen, es ist eine Wäsche, zwischen der verwendet werden muss.

der Blechmann
quelle
Extrem hilfreich! Auf meinem System ==ergab sich schneller als .equal?für Zeichenfolgen- und Symbolvergleiche. Der Symbolvergleich war mehr als dreimal schneller als der Vergleich von Zeichenfolgen.
Melvynkim
33

Symbole sind eine Möglichkeit, Zeichenfolgen und Namen in Rubin darzustellen.

Der Hauptunterschied zwischen Symbolen und Zeichenfolgen besteht darin, dass gleichnamige Symbole initialisiert werden und während einer Rubinsitzung nur einmal im Speicher vorhanden sind.

Sie sind nützlich, wenn Sie dasselbe Wort verwenden müssen, um verschiedene Dinge darzustellen

Nunopolonia
quelle
19

Es gibt einige Zitate aus dem berühmten Buch Agile Web Development with Rails , die hilfreich sein können, um das Symbol ebenfalls zu verstehen :

Rails verwendet Symbole, um Dinge zu identifizieren. Insbesondere werden sie als Schlüssel verwendet, wenn Methodenparameter benannt und in Hashes nachgeschlagen werden.

redirect_to :action => "edit", :id => params[:id]

Sie können sich Symbole als Zeichenfolgenliterale vorstellen, die auf magische Weise zu Konstanten gemacht werden. Alternativ können Sie den Doppelpunkt als "das benannte Ding" betrachten, also: id ist "das Ding mit dem Namen id".

shyan1
quelle
5

In Ruby hat jedes Objekt eine eindeutige Objektkennung. Wenn Sie puts "hello".object_idin Ihren irb schreiben und zweimal auf die Eingabetaste drücken, erhalten Sie zwei verschiedene Rückgabewerte. Wenn Sie jedoch :hello.object_idzwei Mal schreiben, erhalten Sie nur denselben Rückgabewert. Das hätte den Unterschied erklären sollen.

Devin Huang
quelle
Grundsätzlich ist der Doppelpunkt Operator für die Zuweisung eines Symbols
Cesar Jr Rodriguez
2

Wenn Sie verwenden :foo => bar, wird foo ein Symbol sein. Symbole haben den Vorteil, dass sie einzigartig sind. Wenn Sie ein Element im Hash aufrufen, tun Sie dies hash[:foo].

Symbole benötigen weniger Speicher als Zeichenfolgen, was sie auch nützlich macht, wenn Sie Ihr Programm etwas schneller machen möchten.

Charles
quelle
0

Es ist ein Symbol. Grundsätzlich sagen Sie, dass die beiden Elemente des Hash Schlüssel haben blaund bloop, als hätten Sie die Zeichenfolgen "bla"und verwendet "bloop". Sie benötigen jedoch weniger Speicher als Zeichenfolgen und sind einfacher zu tippen.

irgendwie
quelle
0

Alle diese Antworten lassen ein zusätzliches verlockendes Detail aus. Wenn Sie das Symbol stringieren: foo, erhalten Sie ... raten Sie mal ... die Zeichenfolge "foo". Daher

irb(main):025:0>
irb(main):026:0> :foo
=> :foo
irb(main):027:0> "#{:foo}"
=> "foo"
irb(main):028:0>
irb(main):029:0> 'foo' <=> :foo
=> nil
irb(main):030:0> 'foo' <=> :foo.to_s
=> 0
irb(main):031:0>

Daher ist es für Perl-Programmierer Rubys Antwort auf das "bloße Wort".

Frank Carnovale
quelle
-1

Wenn Sie mit Java vertraut sind, wissen Sie möglicherweise, dass Strings in Java unveränderlich sind. Symbole sind in diesem Sinne in Ruby ähnlich. Sie sind unveränderlich, dh eine beliebige Anzahl von Vorkommen eines bestimmten Symbols :symbolwird nur einer einzigen Speicheradresse zugeordnet. Daher wird empfohlen, wo immer möglich Symbole zu verwenden, da dies die Speichernutzung optimiert.

Dhruva Sagar
quelle
1
Die Tatsache, dass Symbole unveränderlich sind, stellt sicher, dass sie in Ihrer gesamten Anwendung immer dieselbe Instanz sind und somit garantiert dasselbe Objekt sind. Überprüfen Sie diese Referenzen: Troubleshooters.com/codecorn/ruby/symbols.htm robertsosinski.com/2009/01/11/… Wenn Sie googeln, finden Sie noch viel mehr.
Dhruva Sagar
Ich spreche von Ihrer Analogie zu Java. Java-Strings sind nicht analog zu Symbolen. Java-String-Literale sind aber nicht alle Strings.
smartnut007
Vielleicht war meine Aussage nicht klar genug. Sie sind nur insofern analog, als sie unveränderlich sind.
Dhruva Sagar
@DhruvaSagar: Die Analogie wäre besser, wenn Sie Objective Cs verwenden würden NSString. Es "foo"wird immer gleich sein "foo", weil interne Zeichenfolgen, auf die gleich ist, nur darauf hingewiesen werden. Die Antwort wäre jedoch immer noch verwirrend.
Rafael Bugajewski