Quel est l'opérateur du côlon dans Ruby?

234

Quand je dis { :bla => 1, :bloop => 2 }, qu'est-ce que ça fait exactement :? J'ai lu quelque part comment cela ressemble à une chaîne, mais en quelque sorte un symbole.

Je ne suis pas très clair sur le concept, quelqu'un pourrait-il m'éclairer?

LuxuryMode
la source
1
doublon possible de Comprendre les symboles en rubis
Mladen Jablanović
7
Essayez de regarder ceci: Le Guide Ruby_Newbie des symboles
Hengjie
Cette vidéo vous explique tout ce que vous devez savoir sur les symboles.
totymedli

Réponses:

249

:fooest un symbole nommé "foo". Les symboles ont la particularité que deux symboles portant le même nom seront identiques:

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

Cela rend la comparaison de deux symboles très rapide (car seule une comparaison de pointeurs est impliquée, par opposition à la comparaison de tous les caractères comme vous le feriez dans une chaîne), et vous n'aurez pas non plus un million de copies du même symbole flottant.

De plus, contrairement aux chaînes, les symboles sont immuables.

Chris Jester-Young
la source
2
demandez-vous simplement pourquoi la chaîne littérale ne prend pas en charge l'internement de chaînes?
onmyway133
5
@ onmyway133 Parce que les chaînes de Ruby sont mutables. L'internat ne s'applique qu'aux valeurs immuables.
Chris Jester-Young
3
a) Pourquoi est-ce "foo".equal? "foo"faux? b) Pouvez-vous faire référence à un symbole n'importe où, ce qui en fait essentiellement des variables globales?
Arc676
2
@ Arc676 1. equal?dans Ruby fait une comparaison d'identité. Chaque littéral de chaîne, comme "foo", crée une nouvelle instance de chaîne. Cela fonctionne de cette façon car les chaînes de Ruby sont mutables. 2. Les symboles sont globaux, mais ressemblent plus à des constantes globales qu'à des variables globales, car les symboles n'ont pas d'état. Ainsi, l'utilisation de symboles n'est pas un contre-modèle à la manière des variables globales.
Chris Jester-Young
2
@ Arc676 "foo" == "foo"# => true
Filip Bartuzi
44

Juste pour démontrer certaines des choses mentionnées dans les réponses:

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

Le lancer génère:

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

Ainsi, la comparaison d'une chaîne à une chaîne utilisant equal?échoue car ce sont des objets différents, même s'ils ont un contenu égal. ==compare le contenu et les vérifications équivalentes avec des symboles sont beaucoup plus rapides.

                 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)

Les deux tests de symboles sont fondamentalement les mêmes en ce qui concerne la vitesse. Après 1000000 d'itérations, il n'y a que 0,004733 seconde de différence, donc je dirais que c'est un lavage entre lequel utiliser.

l'homme d'étain
la source
Extrêmement utile! Sur mon système, les ==résultats ont été plus rapides que .equal?pour les comparaisons de chaînes et de symboles. La comparaison des symboles a produit 3+ fois plus rapidement que les comparaisons de chaînes.
melvynkim
33

Les symboles sont un moyen de représenter des chaînes et des noms en rubis.

La principale différence entre les symboles et les chaînes est que les symboles du même nom sont initialisés et n'existent en mémoire qu'une seule fois lors d'une session de rubis.

Ils sont utiles lorsque vous devez utiliser le même mot pour représenter différentes choses

nunopolonia
la source
19

Il y a quelques citations du célèbre livre Agile Web Development with Rails , qui peuvent également être utiles pour comprendre le symbole :

Rails utilise des symboles pour identifier les choses. En particulier, il les utilise comme clés pour nommer les paramètres des méthodes et rechercher les choses dans des hachages.

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

Vous pouvez considérer les symboles comme des littéraux de chaîne qui sont magiquement transformés en constantes. Alternativement, vous pouvez considérer les deux points comme signifiant "la chose nommée", donc: id est "la chose nommée id".

shyan1
la source
5

En rubis, chaque objet a un identifiant d'objet unique, si vous écrivez puts "hello".object_iddans votre IRB et appuyez sur Retour pendant 2 fois différentes, vous obtiendrez 2 valeurs de retour différentes, mais si vous écrivez :hello.object_id2 fois, vous n'obtiendrez que la même valeur de retour. Cela aurait dû expliquer la différence.

Devin Huang
la source
Fondamentalement, l'opérateur du côlon est d'assigner un symbole
Cesar Jr Rodriguez
2

Si vous utilisez :foo => bar, foo sera un symbole. L'avantage des symboles est qu'ils sont uniques. Lorsque vous appelez un élément du hachage, vous le faites hash[:foo].

Les symboles nécessitent moins de mémoire que les chaînes, ce qui les rend également utiles si vous souhaitez rendre votre programme un peu plus rapide.

Charles
la source
0

C'est un symbole. Fondamentalement, vous dites que les deux éléments du hachage ont des clés blaet bloop, tout comme si vous aviez utilisé les chaînes "bla"et "bloop". Cependant, ils occupent moins de mémoire que les chaînes et sont plus faciles à taper.

gentil
la source
0

Toutes ces réponses omettent un détail supplémentaire alléchant .. si vous stringifiez le symbole: foo, vous obtenez .. devinez quoi .. la chaîne "foo". Par conséquent

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>

Par conséquent .. pour les programmeurs Perl .. c'est la réponse de Ruby au «mot nu».

Frank Carnovale
la source
-1

Si vous connaissez Java, vous savez peut-être que les chaînes en Java sont immuables. Les symboles sont similaires en ce sens dans Ruby. Ils sont immuables, c'est-à-dire que n'importe quel nombre d'occurrences d'un symbole particulier :symbolsera mappé à une seule adresse mémoire. Et, par conséquent, il est recommandé d'utiliser des symboles dans la mesure du possible car il optimise l'utilisation de la mémoire.

Dhruva Sagar
la source
1
Le fait que les symboles soient immuables garantit qu'ils sont toujours la même instance dans toute votre application et, par conséquent, ils sont garantis comme étant le même objet. Vérifiez ces références: troubleshooters.com/codecorn/ruby/symbols.htm robertsosinski.com/2009/01/11/… Vous trouverez des charges plus si vous google.
Dhruva Sagar
Je parle de votre analogie avec Java. Les chaînes Java ne sont pas analogues aux symboles. Les littéraux de chaîne Java ne sont pas toutes des chaînes.
smartnut007
Peut-être que ma déclaration n'était pas assez claire. Ils ne sont analogues entre eux que par le fait qu'ils sont immuables.
Dhruva Sagar
@DhruvaSagar: L'analogie serait mieux si vous avez utilisé de Objective C NSString. Il y "foo"aura toujours égal à "foo", car les chaînes internes identiques sont simplement désignées. Mais la réponse serait encore confuse.
Rafael Bugajewski