Po co używać symboli jako kluczy hashowych w Ruby?

Wiele razy ludzie używają symboli jako kluczy w Ruby hash.

Jaka jest przewaga nad używaniem Sznurka?

Np.:

hash[:name]

Vs.

hash['name']
Author: Max, 2011-11-19

4 answers

TL; DR:

Używanie symboli nie tylko oszczędza czas podczas porównań, ale także oszczędza pamięć, ponieważ są one przechowywane tylko raz.

Symbole Ruby są niezmienne (nie można ich zmienić), co znacznie ułatwia szukanie czegoś

Krótka odpowiedź:

Używanie symboli nie tylko oszczędza czas podczas porównań, ale także oszczędza pamięć, ponieważ są one przechowywane tylko raz.

Symbole w Rubim to w zasadzie "niezmienne ciągi" .. oznacza to, że nie można ich zmienić, a to oznacza, że ten sam symbol, gdy odwołuje się wiele razy w kodzie źródłowym, jest zawsze przechowywany jako ta sama jednostka, np. ma ten sam identyfikator obiektu.

Struny z drugiej strony są mutowalne , mogą być zmieniane w każdej chwili. Oznacza to, że Ruby musi przechowywać każdy łańcuch, o którym wspomniałeś w swoim kodzie źródłowym, w osobnym encji, np. jeśli masz łańcuch "name" wielokrotnie wymieniony w Twój kod źródłowy, Ruby musi przechowywać je wszystkie w oddzielnych obiektach łańcuchowych, ponieważ mogą się one później zmienić(taka jest natura łańcucha Ruby).

Jeśli używasz ciągu znaków jako klucza Hashowego, Ruby musi ocenić łańcuch i spojrzeć na jego zawartość( i obliczyć na nim funkcję skrótu) i porównać wynik z (hashowanymi) wartościami kluczy, które są już zapisane w haśle.

Jeśli używasz symbolu jako klucza Hashowego, jest to niejawne, że jest niezmienny, więc Ruby może w zasadzie po prostu wykonaj Porównanie (funkcji hashowej) object-id z (hashowanymi) object-ID kluczy, które są już zapisane w Hash. (znacznie szybciej)

Minusy: Każdy symbol zajmuje miejsce w tabeli symboli interpretera Ruby, które nigdy nie jest zwalniane. Symbole nigdy nie są zbierane śmieci. Tak więc sprawa narożna ma miejsce, gdy masz dużą liczbę symboli (np. automatycznie wygenerowanych). W takim przypadku powinieneś ocenić, jak wpływa to na rozmiar Twojego Ruby Tłumacz.

Uwagi:

Jeśli porównujesz ciągi znaków, Ruby może porównywać symbole tylko według ich identyfikatorów obiektów, bez konieczności ich oceny. Jest to znacznie szybsze niż porównywanie ciągów, które muszą zostać ocenione.

Jeśli uzyskujesz dostęp do skrótu, Ruby zawsze stosuje funkcję skrótu do obliczania "klucza skrótu" z dowolnego klucza, którego używasz. Możesz sobie wyobrazić coś w rodzaju MD5-hash. A potem Ruby porównuje te "zaszyfrowane Klucze" do siebie.

Długie odpowiedź:

Http://www.reactive.io/tips/2009/01/11/the-difference-between-ruby-symbols-and-strings

Http://www.randomhacks.net/articles/2007/01/20/13-ways-of-looking-at-a-ruby-symbol

 201
Author: Tilo,
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
2018-07-19 21:16:29

Powodem jest wydajność, z wieloma zyskami nad ciągiem:

  1. symbole są niezmienne, więc pytanie "co się stanie, jeśli klucz się zmieni?"nie trzeba pytać.
  2. ciągi znaków są powielane w kodzie i zazwyczaj zajmują więcej miejsca w pamięci.
  3. szukanie skrótu musi obliczać hash kluczy, aby je porównać. Jest to O(n) dla ciągów i stała dla symboli.

Ponadto Ruby 1.9 wprowadził uproszczoną składnię tylko dla hasha z klucze symboli (np. h.merge(foo: 42, bar: 6)), A Ruby 2.0 ma argumenty słów kluczowych , które działają tylko dla kluczy symboli.

uwagi:

1) Możesz być zaskoczony, gdy dowiesz się, że Ruby traktuje klucze String inaczej niż jakikolwiek inny typ. Rzeczywiście:

s = "foo"
h = {}
h[s] = "bar"
s.upcase!
h.rehash   # must be called whenever a key changes!
h[s]   # => nil, not "bar"
h.keys
h.keys.first.upcase!  # => TypeError: can't modify frozen string

Tylko dla kluczy łańcuchowych, Ruby użyje zamrożonej kopii zamiast samego obiektu.

2) litery "b"," a "i" r " są przechowywane tylko raz dla wszystkich wystąpień :bar w programie. Przed Rubim 2.2, to był zły pomysł, aby stale twórz nowe Symbols, które nigdy nie zostały ponownie użyte, ponieważ pozostaną w globalnej tabeli wyszukiwania symboli na zawsze. Ruby 2.2 będzie je zbierać, więc nie martw się.

3) w Rubim 1.8 obliczanie hasha dla symbolu nie zajęło dużo czasu.x, ponieważ ID obiektu zostało użyte bezpośrednio:

:bar.object_id == :bar.hash # => true in Ruby 1.8.7

W Ruby 1.9.x, zmieniło się to wraz ze zmianą hashów z jednej sesji na drugą (w tym z Symbols):

:bar.hash # => some number that will be different next time Ruby 1.9 is ran
 21
Author: Marc-André Lafortune,
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-20 18:31:23

[0] re: jaka jest przewaga nad używaniem Sznurka?

  • Stylizacja: its the Ruby-way
  • (bardzo) nieco szybsze szukanie wartości, ponieważ haszowanie symbolu jest równoznaczne z haszowaniem liczby całkowitej vs haszowaniem ciągu znaków.

  • Wada: zużywa slot w tabeli symboli programu, który nigdy nie jest zwolniony.

 6
Author: Larry K,
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
2011-11-18 21:39:58

Byłbym bardzo zainteresowany kontynuacją dotyczącą frozen strings wprowadzoną w Ruby 2.x.

Kiedy masz do czynienia z wieloma ciągami pochodzącymi z wejścia tekstowego (myślę o PARAMACH HTTP lub payload, na przykład przez Rack), jest o wiele łatwiej używać ciągów wszędzie.

Kiedy masz do czynienia z dziesiątkami z nich, ale nigdy się nie zmieniają( jeśli są twoim biznesowym "słownictwem"), lubię myśleć, że zamrożenie ich może coś zmienić. Nie zrobiłem jeszcze żadnego benchmarka, ale chyba bądź blisko wydajności symboli.

 0
Author: jlecour,
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
2016-08-31 17:25:24