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?
Author: the Tin Man, 2010-02-26

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.

 56
Author: anshul,
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.

 46
Author: Segfault,
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.

 29
Author: jcdyer,
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.

 25
Author: tadman,
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.

 14
Author: Chuck,
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".
 12
Author: meagar,
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.

 10
Author: Mark Fox,
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 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? "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.]

 3
Author: Jörg W Mittag,
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.

 3
Author: Greg Campbell,
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ą.

 0
Author: Dave Munger,
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"

 -2
Author: ahnbizcad,
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