Co to jest operator dwukropka w Ruby?

234

Kiedy mówię { :bla => 1, :bloop => 2 }, co dokładnie robi :? Czytałem gdzieś o tym, jak jest podobny do sznurka, ale jakoś symbol.

Nie do końca rozumiem pojęcie, czy ktoś mógłby mnie oświecić?

LuxuryMode
źródło
1
możliwy duplikat Zrozumienia symboli w Rubim
Mladen Jablanović
7
Spróbuj spojrzeć na to: Przewodnik Ruby_Newbie po symbolach
Hengjie,
Ten film mówi ci wszystko, co musisz wiedzieć o symbolach.
totymedli

Odpowiedzi:

249

:footo symbol o nazwie „foo”. Symbole mają wyraźną cechę polegającą na tym, że dowolne dwa takie same symbole będą identyczne:

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

To sprawia, że ​​porównywanie dwóch symboli jest naprawdę szybkie (ponieważ chodzi tylko o porównanie wskaźnika, w przeciwieństwie do porównywania wszystkich znaków jak w łańcuchu), a ponadto nie będziesz mieć pływających wokół zillionowych kopii tego samego symbolu.

Ponadto, w przeciwieństwie do łańcuchów, symbole są niezmienne.

Chris Jester-Young
źródło
2
Zastanawiam się, dlaczego dosłowny ciąg nie obsługuje internowania łańcucha?
onmyway133,
5
@ onmyway133 Ponieważ ciągi Ruby są zmienne. Internowanie dotyczy tylko niezmiennych wartości.
Chris Jester-Young,
3
a) Dlaczego "foo".equal? "foo"fałsz? b) Czy możesz odwołać się do symbolu w dowolnym miejscu, zasadniczo czyniąc go podobnym do zmiennych globalnych?
Arc676,
2
@ Arc676 1. equal?w Ruby dokonuje porównania tożsamości. Każdy literał łańcuchowy, podobnie jak "foo", tworzy nową instancję łańcucha. Działa to w ten sposób, ponieważ ciągi w Rubim są zmienne. 2. Symbole są globalne, ale bardziej przypominają stałe globalne niż zmienne globalne, ponieważ symbole nie mają stanu. Zatem używanie symboli nie jest antypatternem tak jak zmienne globalne.
Chris Jester-Young
2
@ Arc676 "foo" == "foo"# => true
Filip Bartuzi
44

Aby zademonstrować niektóre rzeczy wymienione w odpowiedziach:

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

Uruchomienie go powoduje:

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

Porównywanie łańcucha z ciągiem przy użyciu equal?kończy się niepowodzeniem, ponieważ są to różne obiekty, nawet jeśli mają równą zawartość. ==porównuje zawartość, a kontrole równoważne z symbolami są znacznie szybsze.

                 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)

Oba testy symboli są zasadniczo takie same pod względem prędkości. Po 1 000 000 iteracji jest tylko 0,004733 sekundowa różnica, więc powiedziałbym, że to pranie pomiędzy, których należy użyć.

Blaszany Człowiek
źródło
Niezwykle pomocny! W moim systemie wynik ==był szybszy niż w .equal?przypadku porównań ciągów i symboli. Porównanie symboli było ponad 3 razy szybsze niż porównywanie ciągów.
melvynkim
33

Symbole są sposobem na reprezentowanie ciągów i nazw w rubinie.

Główną różnicą między symbolami i łańcuchami jest to, że symbole o tej samej nazwie są inicjowane i istnieją w pamięci tylko raz podczas sesji ruby.

Są przydatne, gdy trzeba użyć tego samego słowa do przedstawienia różnych rzeczy

nunopolonia
źródło
19

Jest kilka cytatów ze słynnej książki Agile Web Development with Rails , które mogą być pomocne w zrozumieniu tego symbolu :

Szyny używają symboli do identyfikacji rzeczy. W szczególności używa ich jako kluczy podczas nazywania parametrów metody i wyszukiwania rzeczy w haszach.

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

Możesz myśleć o symbolach jak o literałach łańcuchowych, które są magicznie przekształcane w stałe. Alternatywnie możesz uznać, że dwukropek oznacza „rzecz o nazwie”, więc: id to „rzecz o nazwie id”.

shyan1
źródło
5

W Ruby każdy obiekt ma unikalny identyfikator obiektu, jeśli napiszesz puts "hello".object_idw swoim irb i naciśniesz return 2 razy, otrzymasz 2 różne wartości zwracane, ale jeśli napiszesz :hello.object_id2 razy, otrzymasz tylko tę samą zwracaną wartość. To powinno było wyjaśnić różnicę.

Devin Huang
źródło
Zasadniczo operator dwukropka służy do przypisania symbolu
Cesar Jr Rodriguez
2

Jeśli użyjesz :foo => bar, foo będzie symbolem. Zaletą symboli jest to, że są wyjątkowe. Kiedy wywołujesz element w skrócie, robisz hash[:foo].

Symbole wymagają mniej pamięci niż łańcuchy, co czyni je również przydatnymi, jeśli chcesz, aby twój program był nieco szybszy.

Charles
źródło
0

To jest symbol. Zasadniczo mówisz, że dwa elementy skrótu mają klucze blai bloop, tak jakbyś użył ciągów "bla"i "bloop". Jednak zajmują mniej pamięci niż łańcuchy i są łatwiejsze do pisania.

kindall
źródło
0

Wszystkie te odpowiedzi pomijają jeden dodatkowy kuszący szczegół ... jeśli skreślisz symbol: foo, otrzymasz ... zgadnij co ... ciąg "foo". W związku z tym

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>

Stąd… dla programistów Perla… to odpowiedź Ruby na „gołe słowo”.

Frank Carnovale
źródło
-1

Jeśli znasz język Java, możesz mieć świadomość, że ciągi w języku Java są niezmienne. Symbole są podobne pod tym względem w języku Ruby. Są niezmienne, tzn. Dowolna liczba wystąpień określonego symbolu :symbolzostanie zmapowana tylko na jeden adres pamięci. Dlatego zaleca się używanie symboli tam, gdzie to możliwe, ponieważ optymalizuje wykorzystanie pamięci.

Dhruva Sagar
źródło
1
Fakt, że symbole są niezmienne, gwarantuje, że są one zawsze tą samą instancją w całej aplikacji, a zatem gwarantuje się, że są tym samym obiektem. Sprawdź te referencje: Troubleshooters.com/codecorn/ruby/symbols.htm robertsosinski.com/2009/01/11/ ... Znajdziesz więcej ładunków, jeśli google.
Dhruva Sagar
Mówię o twojej analogii do Javy. Ciągi Java nie są analogiczne do symboli. Literały ciągów Java są, ale nie wszystkie ciągami.
smartnut007
Być może moje oświadczenie nie było wystarczająco jasne. Są do siebie analogiczni tylko pod tym względem, że są niezmienni.
Dhruva Sagar
@DhruvaSagar: Analogia byłoby lepiej, jeśli używane c-Celu NSString. Nie "foo"zawsze będzie równa "foo", ponieważ wewnętrznie struny, które są takie same są tylko wskazał. Odpowiedź byłaby jednak myląca.
Rafael Bugajewski