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ć?
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ć?
Odpowiedzi:
:foo
to 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.
"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?
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.
"foo" == "foo"
# => true
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ć.
==
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.
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
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”.
W Ruby każdy obiekt ma unikalny identyfikator obiektu, jeśli napiszesz puts "hello".object_id
w swoim irb i naciśniesz return 2 razy, otrzymasz 2 różne wartości zwracane, ale jeśli napiszesz :hello.object_id
2 razy, otrzymasz tylko tę samą zwracaną wartość. To powinno było wyjaśnić różnicę.
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”.
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 :symbol
zostanie zmapowana tylko na jeden adres pamięci. Dlatego zaleca się używanie symboli tam, gdzie to możliwe, ponieważ optymalizuje wykorzystanie pamięci.
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.