Зачем использовать символы в качестве хэш-ключей в Ruby?



очень часто люди используют символы в качестве ключей в хэш-Рубин.



в чем преимущество использования строки?



например:



hash[:name]


и



hash['name']
665   4  

4 ответов:

TL; DR:

использование символов не только экономит время при проведении сравнений, но и экономит память, поскольку они хранятся только один раз.

символы Ruby неизменяемы (не могут быть изменены), что делает поиск чего-то намного проще

короткий(иш) ответ:

использование символов не только экономит время при проведении сравнений, но и экономит память, поскольку они хранятся только однажды.

символы в Ruby в принципе "неизменяемые строки" .. это означает, что они не могут быть изменены, и это означает, что один и тот же символ, на который ссылаются много раз в вашем исходном коде, всегда хранится как одна и та же сущность, например, имеет один и тот же идентификатор объекта.

строки с другой стороны изменчивы, они могут быть изменены в любое время. Это означает, что Ruby должен хранить каждую строку, которую вы упоминаете на протяжении всего вашего исходный код в этом отдельном объекте, например, если у вас есть строка "имя", несколько раз упомянутая в исходном коде, Ruby должен хранить их все в отдельных строковых объектах, потому что они могут измениться позже (это природа строки Ruby).

Если вы используете строку в качестве хэш-ключа, Ruby должен оценить строку и посмотреть на ее содержимое (и вычислить хэш-функцию на этом) и сравнить результат с (хэшированными) значениями ключей, которые уже хранятся в Хэш.

Если вы используете символ в качестве хэш-ключа, подразумевается, что он неизменен, поэтому Ruby может в основном просто сравнивать (хэш-функцию) object-id с (хэшированными) object-ID ключей, которые уже хранятся в хэше. (гораздо быстрее)

недостаток: Каждый символ использует слот в таблице символов интерпретатора Ruby, который никогда не освобождается. Символы никогда не собирают мусор. Таким образом, угловой случай - это когда у вас есть большое количество символы (например, автоматически генерируемые). В этом случае вы должны оценить, как это влияет на размер вашего интерпретатора Ruby.

Примечания:

Если вы делаете сравнение строк, Ruby может сравнивать символы только по их идентификаторам объектов, не оценивая их. Это гораздо быстрее, чем сравнение строк, которые должны быть оценены.

Если вы получаете доступ к хэшу, Ruby всегда применяет хэш-функцию для вычисления "хэш-ключа" из любого ключа, который вы используете. Вы можете представьте себе что-то вроде MD5-хэша. А потом Руби сравнивает эти "хэшированные ключи" друг с другом.

ответ:

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

причина заключается в эффективности, с несколькими усилениями над строкой:

  1. символы неизменны, поэтому вопрос "Что произойдет, если ключ изменится?- не нужно спрашивать.
  2. строки дублируются в коде и обычно занимают больше места в памяти.
  3. хэш-поиск должен вычислить хэш ключей, чтобы сравнить их. Это O(n) для строк и констант для символов.

кроме того, Ruby 1.9 ввел a упрощенный синтаксис только для хэша с ключами символов (например,h.merge(foo: 42, bar: 6)), и Ruby 2.0 имеет аргументов ключевого слова это работает только для символов ключей.

Примечания:

1) Вы можете быть удивлены, узнав, что Рубин лечит String клавиши отличаются от любого другого типа. Действительно:

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

только для строковых ключей Ruby будет использовать замороженную копию вместо самого объекта.

2) буквы "b", "a" и "r" сохраняются только раз для всех случаев :bar в программе. Прежде чем Руби 2.2, это была плохая идея, чтобы постоянно создавать новые Symbols которые никогда не использовались повторно, так как они навсегда останутся в глобальной таблице поиска символов. Руби 2.2 будет мусор собирать их, так что не беспокойтесь.

3) На самом деле, вычисление хэша для символа не заняло много времени в Ruby 1.8.x, поскольку идентификатор объекта был использован непосредственно:

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

В Ruby 1.9.x, это изменилось, поскольку хэши меняются от одного сеанса к другому (включая тех из Symbols):

:bar.hash # => some number that will be different next time Ruby 1.9 is ran

Re: в чем преимущество использования строки?

  • стиль: его рубиновый путь
  • (очень) немного более быстрый поиск значений, так как хэширование символа эквивалентно хэшированию целого числа против хэширования строки.

  • недостаток: потребляет слот в таблице символов программы, который никогда не освобождается.

Мне было бы очень интересно следить за замороженными строками, введенными в Ruby 2.x.

когда вы имеете дело с многочисленными строками, поступающими из текстового ввода (я имею в виду http-параметры или полезную нагрузку, например, через стойку), гораздо проще использовать строки везде.

когда вы имеете дело с десятками из них, но они никогда не меняются (если они ваш бизнес "словарь"), мне нравится думать, что замораживание их может иметь значение. Я еще не сделал никакого теста, но я думаю, это было бы близко к производительности символов.

Comments

    Ничего не найдено.