Pytanie Jak rozumieć symbole w Ruby


Pomimo czytania "Zrozumienie symboli ruby", Nadal jestem zdezorientowany przez 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 tej samej lokalizacji pamięci, to jak to jest, że zawierają różne wartości? Spodziewałbym się, że ta sama lokalizacja pamięci zawiera tę samą wartość.

To cytat z linku:

W przeciwieństwie do ciągów, symbole o tej samej nazwie są inicjowane i istnieją w pamięci tylko raz podczas sesji ruby

Nie rozumiem, w jaki sposób udaje się rozróżnić wartości zawarte w tej samej lokalizacji pamięci.

Rozważmy 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 to oba skróty, to w porządku. :ruby jednak jest symbolem. Gdybyśmy wyprowadzili następujące dane:

patient1.each_key {|key| puts key.to_s}

Więc co będzie wyjście? "red", lub "programming"?

Zapominając o haszach na sekundę, myślę, że symbolem jest wskaźnik do wartości. Moje pytania to:

  • Czy mogę przypisać wartość do symbolu?
  • Czy symbol jest tylko wskaźnikiem do zmiennej z wartością?
  • Jeśli symbole są globalne, czy oznacza to, że symbol zawsze wskazuje na jedno?

76
2018-02-26 13:22


pochodzenie


Wypisze ": ruby", ponieważ drukujesz symbol. Jeśli powiesz puts patient1[:ruby], wydrukuje "czerwony", jeśli powiesz puts patient2[:ruby], wydrukuje "programowanie". - R.O.S.S
Symbol NIE jest wskaźnikiem do wartości. Wewnętrznie symbol jest po prostu liczbą całkowitą. - akuhn


Odpowiedzi:


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, o ile jego zawartość jest taka sama, będzie odnosić się do tego samego obiektu w pamięci. Nie stanowi to problemu, ponieważ symbol jest symbolem niezmienny obiekt. Ciągi są zmienne.


(W odpowiedzi na komentarz poniżej)

W oryginalnym artykule wartość nie jest przechowywana w symbolu, jest przechowywana w haszowaniu. Rozważ to:

hash1 = { "string" => "value"}
hash2 = { "string" => "value"}

Tworzy to sześć obiektów w pamięci - cztery obiekty ciągów i dwa obiekty mieszające.

hash1 = { :symbol => "value"}
hash2 = { :symbol => "value"}

Tworzy tylko pięć obiektów w pamięci - jeden symbol, dwa ciągi i dwa obiekty kryptograficzne.


55
2018-02-26 13:35



Przykład w łączu pokazuje jednak symbole zawierające różne wartości, ale symbol ma tę samą nazwę i tę samą lokalizację pamięci. Kiedy są na wyjściu, mają różne wartości, to część, której nie dostaję. Z pewnością powinny zawierać tę samą wartość? - Kezzer
Właśnie dokonałem edycji, aby spróbować wyjaśnić, w jaki sposób jestem nadal zdezorientowany. Mój mózg nie może obliczyć;) - Kezzer
Symbole nie zawierają wartości, one są wartości. Hassy zawierają wartości. - Mladen Jablanović
To jest Hash (stworzony przez {... => ...} w twoim kodzie), który przechowuje pary klucz / wartość, a nie Symbols same. The Symbols (np. :symbol lub :sym lub :ruby) są kluczami w parach. Tylko jako część Hash czy "wskazują" na cokolwiek. - James A. Rosen
Symbol jest używany jako klucz w haśle, a nie jako wartość, dlatego może być inny, podobnie jak przy użyciu słowa klucz1 = "ruby" i hash1 = {klucz1 => "wartość" ...} hash2 = { key1 => 'value2' ...}. - Joshua Olson


Udało mi się złapać symbole, gdy pomyślałem o tym w ten sposób. Ciąg ruby ​​jest obiektem, który ma wiele metod i właściwości. Ludzie lubią używać łańcuchów dla kluczy, a gdy łańcuch jest używany dla klucza, wszystkie te dodatkowe metody nie są używane. Zrobili więc symbole, które są obiektami typu string z usuniętą całą funkcjonalnością, z wyjątkiem tego, co jest potrzebne, aby był dobrym kluczem.

Po prostu myśl o symbolach jako stałych ciągach.


45
2018-02-26 14:40



Czytając posty, ten prawdopodobnie ma dla mnie największy sens. : rubin jest po prostu przechowywany gdzieś w pamięci, jeśli gdzieś używam ruby, a potem znów "ruby", to tylko duplikacja. Używanie symboli jest sposobem na ograniczenie powielania wspólnych danych. Jak mówisz, ciągłe struny. Sądzę, że istnieje jakiś ukryty mechanizm, który ponownie znajdzie ten symbol? - Kezzer
@ Kezzer Ta odpowiedź jest naprawdę dobra i wydaje mi się słuszna, ale twój komentarz mówi coś innego i jest błędny lub wprowadzający w błąd, twój komentarz mówi o powielaniu danych za pomocą ciągów i że to jest powód, dla którego symbole są błędne lub wprowadzają w błąd. Wielokrotny symbol nie zużyje więcej miejsca w pamięci, ale możesz mieć to również dla napisów w wielu językach, np niektóre języki programowania, jeśli piszesz "abc" i gdzie indziej "abc" kompilator widzi, że jest to ten sam ciąg wartości i przechowuje go w tym samym miejscu, czyniąc go tym samym obiektem, który nazywa się internging string, a c # to robi. - barlop


Symbol :ruby nie zawiera "red" lub "programming". Symbol :ruby jest tylko symbolem :ruby. To twoje hashe, patient1 i patient2 każda zawiera te wartości, w każdym przypadku wskazywanym przez ten sam klucz.

Pomyśl o tym w ten sposób: jeśli wejdziesz do salonu w bożonarodzeniowy poranek i zobaczysz dwa pudełka z metką na nich z napisem "Kezzer". On ma skarpetki, a drugi ma węgiel. Nie będziesz się mylić i zapytać, jak "Kezzer" może zawierać skarpetki i węgiel, mimo że jest to to samo imię. Ponieważ nazwa nie zawiera (gównianych) prezentów. To tylko wskazuje na nich. Podobnie, :ruby nie zawiera wartości w haśle, po prostu wskazuje na nie.


28
2018-02-26 14:37



Ta odpowiedź ma sens. - Vass
proszę umieść to w oficjalnych dokumentach ruby - dit
Brzmi to jak całkowita mieszanka skrótów i symboli. Symbol nie wskazuje na wartość, jeśli chcesz powiedzieć, że robi się w haszowaniu, cóż, może to być dyskusyjne, ale symbol nie musi być w haszowaniu. Możesz powiedzieć mystring = :steveT   symbol nic nie wskazuje. Klucz w haszsie ma przypisaną wartość, a kluczem może być symbol. Ale symbol nie musi być w haszowaniu. - barlop


Możesz przypuszczać, że deklaracja, którą stworzyłeś, określa wartość Symbolu jako czegoś innego niż to, co jest. W rzeczywistości symbol jest po prostu "internalizowaną" wartością ciągu, która pozostaje stała. Dzieje się tak dlatego, że są przechowywane przy użyciu prostego identyfikatora liczby całkowitej, który jest często używany, ponieważ jest bardziej wydajny niż zarządzanie dużą liczbą ciągów o zmiennej długości.

Weź przykład ze swojego przykładu:

patient1 = { :ruby => "red" }

Powinno to być odczytane jako: "zadeklaruj zmienną patient1 i określ ją jako Hash, a w tym sklepie wartość" red "pod kluczem (symbol" ruby ​​")"

Innym sposobem pisania tego jest:

patient1 = Hash.new
patient1[:ruby] = 'red'

puts patient1[:ruby]
# 'red'

Podczas wykonywania zadania trudno się dziwić, że wynik, jaki otrzymasz, jest identyczny z tym, który został przez Ciebie przypisany.

Koncepcja Symbol może być nieco myląca, ponieważ nie jest cechą większości innych języków.

Każdy obiekt String jest odrębny, nawet jeśli wartości są identyczne:

[ "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

Przekształcanie ciągów znaków w symbole mapuje identyczne wartości do tego samego unikalnego symbolu:

[ "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 Symbol do String tworzy odrębny ciąg za każdym razem:

[ :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ści Symbolu jako pobieranych 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=, ...

W miarę definiowania nowych symboli przez dwukropek-notację lub przy użyciu .to_sym ta tabela będzie rosnąć.


25
2018-02-26 15:34





Symbole nie są wskaźnikami. Nie zawierają wartości. Symbole po prostu . :ruby jest symbolem :ruby i to wszystko, co do niego należy. Nie zawiera wartości, nie ma zrobić cokolwiek, po prostu istnieje jako symbol :ruby. Symbol :ruby jest wartością taką jak numer 1. Nie wskazuje ona na inną wartość niż ta, którą ma numer 1.


14
2018-02-26 18:31



Świetna annalogia do liczby - jperelli
Czy to jest jak haszysz? - Vass


patient1.each_key {|key| puts key.to_s}

Więc co będzie wyjście? "czerwony", lub   "programowanie"?

Ani też nie wyświetli "ruby".

Mylicie symbole i hashe. Nie są powiązane, ale są przydatne razem. Ten symbol jest :ruby; nie ma nic wspólnego z wartościami w haśle, a jego wewnętrzna reprezentacja zawsze będzie taka sama, a jego "wartość" (po przekonwertowaniu na ciąg) zawsze będzie "ruby".


12
2018-02-26 14:41





W skrócie

Symbole rozwiązują problem tworzenia czytelnych dla człowieka, niezmiennych reprezentacji, które mają również tę zaletę, że są łatwiejsze do wykonywania w czasie wykonywania niż łańcuchy. 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 tworzone są złożone, zagnieżdżone struktury danych z czytelnymi odniesieniami. The haszysz jest częstym przypadkiem użycia gdzie mapujesz wartości na unikalne klucze - co najmniej unikalne dla każdej instancji. Nie możesz mieć więcej niż jednego "czerwonego" klucza na hasz.

Jednak bardziej wydajne jest używanie indeksu liczbowego zamiast kluczy łańcuchowych. Tak więc symbole zostały wprowadzone jako kompromis między szybkością i czytelnością. Symbole są łatwiejsze w rozwiązywaniu niż równoważny ciąg znaków. Dzięki czytelności ludzkiej i łatwej do opanowania przez środowisko wykonawcze symbole są idealnym dodatkiem do dynamicznego języka.

Korzyści

Ponieważ symbole są niezmienne, można je udostępniać w środowisku wykonawczym. Jeśli dwie instancje hash mają wspólne leksykograficzne lub semantyczne zapotrzebowanie na czerwony element, symbol: czerwony użyłby mniej więcej połowy pamięci, którą ciąg "czerwony" wymagałby dwóch skrótów.

Ponieważ: kolor czerwony zawsze powraca do tej samej lokalizacji w pamięci, może być ponownie użyty w setkach haszy bez prawie żadnego zwiększenia pamięci, podczas gdy użycie "czerwonego" doda koszt pamięci, ponieważ każda instancja hash będzie musiała przechowywać ciąg zmienny kreacja.

Nie wiem, w jaki sposób Ruby faktycznie implementuje symbole / ciąg znaków, ale wyraźnie symbol oferuje mniej nakładu na wdrożenie w środowisku wykonawczym, ponieważ jest to stała reprezentacja. Symbole plus mają jeden znak mniej czcionki niż cytowany ciąg znaków, a mniej pisanie to odwieczna pogoń za prawdziwymi Rubyistami.

Podsumowanie

Z symbolem takim jak: czerwony uzyskujesz czytelność reprezentacji ciągów przy mniejszym obciążeniu ze względu na koszt operacji porównywania ciągów i konieczność przechowywania każdej instancji łańcucha w pamięci.


10
2017-09-03 22:10





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 to oba skróty, to w porządku. :ruby jednak jest symbolem. Gdybyśmy wyprowadzili następujące dane:

patient1.each_key {|key| puts key.to_s}

Więc co będzie wyjście? "czerwony" lub "programowanie"?

Nie, oczywiście. Wyjście będzie ruby. Co, BTW, mogłeś się dowiedzieć w krótszym czasie, niż zajęło Ci wpisanie pytania, po prostu wpisując je w IRB.

Czemu by tak być red lub programming? Symbolika zawsze oceniajcie sami. Wartość symbolu :ruby jest symbolem :ruby sam i ciąg znaków reprezentujący symbol :ruby jest wartością ciągu "ruby".

[BTW: puts zawsze konwertuje swoje argumenty na łańcuchy. Nie ma potrzeby dzwonić to_s na tym.]


3
2018-02-26 14:29



Nie mam IRB na obecnej maszynie, nie byłbym w stanie go zainstalować, więc dlaczego, więc przepraszam za to. - Kezzer
@Kezzer: Bez obaw, byłem po prostu ciekawy. Czasami zakopujesz się tak głęboko w problem, że nie możesz nawet zobaczyć najprostszych rzeczy. Kiedy w zasadzie wyciąłem i wkleiłem twoje pytanie do IRB, po prostu zastanawiałem się: "dlaczego sam tego nie zrobił?" I nie martw się, nie jesteś pierwszy (ani nie będziesz ostatni), który pyta "co to za wydruk", gdy odpowiedź brzmi: "po prostu uruchom!" BTW: oto twoja natychmiastowa IRB, gdziekolwiek, kiedykolwiek, bez instalacji: TryRuby.Org Lub Ruby-Versions.Net daje dostęp SSH do wszystkich wersji MRI kiedykolwiek wydanych + YARV + JRuby + Rubinius + REE. - Jörg W Mittag
Dzięki, po prostu baw się z tym teraz. Wciąż jestem trochę zdezorientowany, więc przechodzę to jeszcze raz. - Kezzer


Polecam lekturę Artykuł w Wikipedii na temat tabel mieszających - Myślę, że to pomoże ci zorientować się w czym {:ruby => "red"} naprawdę znaczy.

Kolejne ćwiczenie, które może pomóc w zrozumieniu sytuacji: rozważ {1 => "red"}. Semantycznie nie oznacza to "ustaw wartość 1 do "red"", co jest niemożliwe w Ruby, a raczej oznacza" stwórz Haszysz obiekt i zapisz wartość "red" za klucz 1.


3
2018-02-26 17:11





Jestem nowy w Ruby, ale myślę (mam nadzieję?), Że jest to prosty sposób na obejrzenie tego ...

Symbol nie jest zmienną ani stałą. Nie ma wartości lub wskazuje na wartość. Symbol JEST wartością.

Wszystko, co jest, to ciąg bez obiektu nad głową. Tekst i tylko tekst.

Więc to:

"hellobuddy"

Czy to samo:

:hellobuddy

Z wyjątkiem tego, że nie możesz tego zrobić, na przykład: hellobuddy.upcase. Jest to wartość ciągu i TYLKO wartość ciągu.

Podobnie:

greeting =>"hellobuddy"

Czy to samo:

greeting => :hellobuddy

Ale znowu, bez obiektu tekstowego narzutowego.


0
2018-01-10 20:10