Jak rozumieć symbole w Ruby
Pomimo czytania "Understanding Ruby Symbols ", nadal jestem zdezorientowany reprezentacją danych w pamięci, jeśli chodzi o używanie symboli. Jeśli symbol, dwa z nich zawarte w różnych obiektach, istnieją w tym samym miejscu pamięci, to jak to jest, że zawierają różne wartości? Spodziewałem się, że to samo miejsce pamięci zawiera tę samą wartość.
To cytat z linku:
W przeciwieństwie do łańcuchów, symbole o tej samej nazwie są inicjalizacja i istnienie w pamięci tylko raz podczas sesji ruby
Nie rozumiem, w jaki sposób udaje się odróżnić wartości zawarte w tym samym miejscu pamięci.
Rozważ ten przykład:
patient1 = { :ruby => "red" }
patient2 = { :ruby => "programming" }
patient1.each_key {|key| puts key.object_id.to_s}
3918094
patient2.each_key {|key| puts key.object_id.to_s}
3918094
patient1
i patient2
Oba są hashami, w porządku. :ruby
jest jednak symbolem. Jeśli mamy wypisać:
patient1.each_key {|key| puts key.to_s}
To co będzie wynikiem? "red"
, czy "programming"
?
Zapominając na chwilę o hashach, myślę, że symbol jest Wskaźnik do wartości. Mam następujące pytania:
- Czy mogę przypisać wartość symbolowi?
- czy symbol jest tylko wskaźnikiem do zmiennej z wartością w niej?
- jeśli symbole są globalne, czy oznacza to, że symbol zawsze wskazuje na jedną rzecz?
11 answers
Rozważ to:
x = :sym
y = :sym
(x.__id__ == y.__id__ ) && ( :sym.__id__ == x.__id__) # => true
x = "string"
y = "string"
(x.__id__ == y.__id__ ) || ( "string".__id__ == x.__id__) # => false
Tak więc, jakkolwiek tworzysz obiekt symbolu, dopóki jego zawartość jest taka sama, będzie on odnosił się do tego samego obiektu w pamięci. Nie jest to problemem, ponieważ symbol jest obiektem niezmiennym . Struny są zmienne.
(w odpowiedzi na komentarz poniżej)
W oryginalnym artykule, wartość nie jest przechowywana w symbolu, jest przechowywana w hash. Rozważ to:
hash1 = { "string" => "value"}
hash2 = { "string" => "value"}
To tworzy sześć obiektów w pamięci -- cztery obiekty string i dwa obiekty hash.
hash1 = { :symbol => "value"}
hash2 = { :symbol => "value"}
To tworzy tylko pięć obiektów w pamięci-jeden symbol, dwa łańcuchy i dwa obiekty hash.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-07 18:54:45
Byłem w stanie grock symbole, kiedy myślałem o tym w ten sposób. Łańcuch Ruby jest obiektem, który ma kilka metod i właściwości. Ludzie lubią używać ciągów do kluczy, a gdy ciąg jest używany do klucza, to wszystkie te dodatkowe metody nie są używane. Stworzyli więc symbole, które są obiektami ciągowymi z usuniętymi wszystkimi funkcjami, z wyjątkiem tych, które są potrzebne, aby był to dobry klucz.
Pomyśl tylko o symbolach jako ciągach ciągów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 22:54:04
Symbol :ruby
nie zawiera "red"
Ani "programming"
. Symbol :ruby
jest tylko symbolem :ruby
. To twoje skróty patient1
i patient2
zawierają te wartości, w każdym przypadku wskazywane przez ten sam klucz.
Pomyśl o tym w ten sposób: jeśli wejdziesz do salonu w świąteczny poranek i zobaczysz dwa pudełka z metką z napisem "Kezzer". On ma skarpetki w środku, a drugi ma węgiel. Nie będziesz się mylić i zapytać, jak "Kezzer" może zawierać zarówno skarpety, jak i węgiel, nawet jeśli to ta sama nazwa. Bo nazwa nie zawiera (gównianych) prezentów. To tylko wskazuje na nich. Podobnie, :ruby
nie zawiera wartości w Twoim hashu, tylko wskazuje na nie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-26 14:37:33
Możesz przypuszczać, że deklaracja, którą złożyłeś określa wartość symbolu jako coś innego niż to, czym jest. W rzeczywistości Symbol jest po prostu "zinternalizowaną" wartością łańcuchową, która pozostaje stała. To dlatego, że są one przechowywane przy użyciu prostego identyfikatora integer, że są one często używane, ponieważ jest to bardziej efektywne niż zarządzanie dużą liczbą ciągów o zmiennej długości.
Weźmy przykład:
patient1 = { :ruby => "red" }
Należy to odczytać jako: "declare a variable patient1 i zdefiniuj go jako Hash, a w tym przechowuj wartość 'red' pod kluczem (symbol 'ruby')"
Inny sposób zapisu to:
patient1 = Hash.new
patient1[:ruby] = 'red'
puts patient1[:ruby]
# 'red'
Gdy robisz zadanie, trudno się dziwić, że wynik, który otrzymujesz, jest identyczny z tym, z którym go przypisałeś.
Pojęcie symbolu może być nieco mylące, ponieważ nie jest cechą większości innych języków.
Każdy obiekt String jest odrębny, nawet jeśli wartości są identyczny:
[ "foo", "foo", "foo", "bar", "bar", "bar" ].each do |v|
puts v.inspect + ' ' + v.object_id.to_s
end
# "foo" 2148099960
# "foo" 2148099940
# "foo" 2148099920
# "bar" 2148099900
# "bar" 2148099880
# "bar" 2148099860
Każdy Symbol o tej samej wartości odnosi się do tego samego obiektu:
[ :foo, :foo, :foo, :bar, :bar, :bar ].each do |v|
puts v.inspect + ' ' + v.object_id.to_s
end
# :foo 228508
# :foo 228508
# :foo 228508
# :bar 228668
# :bar 228668
# :bar 228668
Konwersja łańcuchów na symbole odwzorowuje identyczne wartości na ten sam unikalny Symbol:
[ "foo", "foo", "foo", "bar", "bar", "bar" ].each do |v|
v = v.to_sym
puts v.inspect + ' ' + v.object_id.to_s
end
# :foo 228508
# :foo 228508
# :foo 228508
# :bar 228668
# :bar 228668
# :bar 228668
Podobnie, konwersja z symbolu na łańcuch tworzy za każdym razem odrębny łańcuch:
[ :foo, :foo, :foo, :bar, :bar, :bar ].each do |v|
v = v.to_s
puts v.inspect + ' ' + v.object_id.to_s
end
# "foo" 2148097820
# "foo" 2148097700
# "foo" 2148097580
# "bar" 2148097460
# "bar" 2148097340
# "bar" 2148097220
Możesz myśleć o wartościach symboli jako pobranych z wewnętrznej tabeli Hash i możesz zobaczyć wszystkie wartości, które zostały zakodowane do symboli za pomocą prostego wywołania metody:
Symbol.all_values
# => [:RUBY_PATCHLEVEL, :vi_editing_mode, :Separator, :TkLSHFT, :one?, :setuid?, :auto_indent_mode, :setregid, :back, :Fail, :RET, :member?, :TkOp, :AP_NAME, :readbyte, :suspend_context, :oct, :store, :WNOHANG, :@seek, :autoload, :rest, :IN_INPUT, :close_read, :type, :filename_quote_characters=, ...
Jak zdefiniujesz nowe symbole albo przez dwukropek albo przez użycie .to_sym ta tabela będzie rosła.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-26 15:41:23
Symbole nie są wskaźnikami. Nie zawierają wartości. Symbole po prostu to. :ruby
jest symbolem :ruby
i to wszystko. Nie zawiera wartości, nie robi niczego, po prostu istnieje jako symbol :ruby
. Symbol :ruby
jest wartością tak samo jak liczba 1. Nie wskazuje na inną wartość tak samo jak liczba 1.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-26 18:31:06
patient1.each_key {|key| puts key.to_s}
To co będzie wynikiem? "czerwony" lub "programowanie"?
Ani nie, wyświetli "ruby".
Mylisz Symbole i skróty. Nie są spokrewnione, ale są przydatne razem. Symbol o którym mowa to:ruby
; nie ma on nic wspólnego z wartościami w hashu, a jego wewnętrzna reprezentacja całkowita będzie zawsze taka sama, a jego " wartość "(po przekonwertowaniu na łańcuch) zawsze będzie "ruby".Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-26 14:41:47
W skrócie
Symbole rozwiązują problem tworzenia czytelnych dla człowieka, niezmiennych reprezentacji, które mają również tę zaletę, że są prostsze do wyszukiwania przez runtime niż łańcuchy znaków. Pomyśl o tym jak o nazwie lub etykiecie, którą można ponownie wykorzystać.
Dlaczego: czerwony jest lepszy niż"czerwony"
W dynamicznych językach obiektowych tworzy się złożone, zagnieżdżone struktury danych z czytelnymi referencjami. hash jest powszechnym przypadkiem użycia , w którym mapujesz wartości do unikalne klucze-unikalne, przynajmniej dla każdej instancji. Nie możesz mieć więcej niż jednego "czerwonego" klucza na hash.
Jednak bardziej wydajne byłoby użycie indeksu numerycznego zamiast kluczy łańcuchowych. Wprowadzono więc symbole jako kompromis między szybkością a czytelnością. Symbole rozwiązują się znacznie łatwiej niż odpowiedni ciąg znaków. Dzięki czytelności dla człowieka i łatwości rozwiązywania symboli w środowisku uruchomieniowym są idealnym dodatkiem do dynamicznego języka.
Korzyści
Od symbole są niezmienne, mogą być współdzielone w czasie wykonywania. Jeśli dwie instancje hash mają wspólną leksykograficzną lub semantyczną potrzebę dla czerwonego elementu, symbol :red użyje mniej więcej połowy pamięci wymaganej przez łańcuch "red" dla dwóch skrótów.
Ponieważ: red zawsze wraca do tego samego miejsca w pamięci, może być ponownie użyty w stu wystąpieniach skrótu bez prawie żadnego zwiększenia pamięci, podczas gdy użycie "red" spowoduje zwiększenie kosztu pamięci, ponieważ każda instancja skrótu musi być przechowywana zmienny ciąg podczas tworzenia.
Nie wiem, w jaki sposób Ruby faktycznie implementuje symbole/ciąg znaków, ale wyraźnie symbol oferuje mniej narzutu implementacji w trybie runtime, ponieważ jest stałą reprezentacją. Plus symbole wymagają o jeden znak mniej do wpisania niż cytowany ciąg, a mniej wpisywania to wieczne dążenie do prawdziwych Rubyistów.
Podsumowanie
Za pomocą symbolu takiego jak: red otrzymujesz czytelność reprezentacji łańcuchów z mniejszym obciążeniem ze względu na koszt porównania łańcuchów operacje i konieczność przechowywania każdej instancji ciągu w pamięci.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-16 23:40:30
patient1 = { :ruby => "red" } patient2 = { :ruby => "programming" } patient1.each_key {|key| puts key.object_id.to_s} 3918094 patient2.each_key {|key| puts key.object_id.to_s} 3918094
patient1
ipatient2
Oba są hashami, w porządku.:ruby
jest jednak symbolem. Jeśli mamy wypisać:patient1.each_key {|key| puts key.to_s}
To co będzie wynikiem? "czerwony", czy"programowanie"?
Żaden, oczywiście. Wyjście To ruby
. Które, BTW, można było dowiedzieć się w czasie krótszym niż zajęło ci wpisać pytanie, po prostu wpisując go do IRB zamiast.
Dlaczego miałby być red
czy programming
? Symbole zawsze oceniaj na siebie. Wartość symbolu :ruby
jest samym symbolem :ruby
, a reprezentacja łańcuchowa symbolu :ruby
jest wartością łańcuchową "ruby"
.
[BTW: puts
zawsze konwertuje swoje argumenty na łańcuchy znaków. Nie ma potrzeby, aby zadzwonić to_s
na to.]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-26 14:29:12
Polecam przeczytanie artykułuWikipedii na temat tabel hashowych - myślę, że pomoże Ci to zrozumieć, co naprawdę oznacza {:ruby => "red"}
.
Kolejne ćwiczenie, które może pomóc ci zrozumieć sytuację: rozważ {1 => "red"}
. Semantycznie nie oznacza to " ustaw wartość 1
na "red"
", co jest niemożliwe w Rubim. Oznacza to raczej " Utwórz obiekt Hash i zachowaj wartość "red"
dla klucza 1
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-26 17:11:28
Jestem nowy w Ruby, ale myślę (hope?) jest to prosty sposób spojrzenia na to...
Symbol nie jest zmienną ani stałą. Nie oznacza ani nie wskazuje na wartość. Symbol jest wartością.
Wszystko, co jest, jest ciągiem bez obiektu nad głową. Tekst i tylko tekst.
Więc to:
"hellobuddy"
Jest takie samo jak to:
:hellobuddy
Z wyjątkiem tego, że nie możesz zrobić np.: hellobuddy.upcase. Jest to wartość łańcuchowa i tylko wartość łańcuchowa.
Podobnie, to:
greeting =>"hellobuddy"
Jest takie samo jak to:
greeting => :hellobuddy
Ale znowu, bez obiektu string nad głową.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-10 20:10:41
"wskazywanie" jest regulowane przez hash, a nie przez symbol.
Symbol jest własną unikalną rzeczą, jak obiekt instancji. lub innego typu danych.
(w rzeczywistości można myśleć o symbolach jako o stałych łańcuchowych, podczas gdy łańcuch składający się z tych samych znaków, co symbol, byłby obiektem instancji klasy String. Zaletą jest zmniejszenie liczby tworzonych obiektów, mniejsze zużycie pamięci, zmniejszenie funky zachowania z powodu odwoływania się do różnych obiektów, a nie ten sam obiekt symbolu).
Za pomocą :ruby
, "red"
, "programming"
, patient1
, i patient2
Hash patient1
patrzy na symbol :ruby
, a następnie mówi: "Och, to odpowiada "red"
Hash patient2
patrzy na symbol :ruby
, a następnie mówi: "Och, to odpowiada "programming"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-18 19:09:49