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ć?



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.


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ć.


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


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”.


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ę.


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.


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.


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”.


-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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.