Много раз люди используют символы в качестве ключей в хеше Ruby.
Какое преимущество перед использованием строки?
например:.
hash[:name]
против.
hash['name']
Много раз люди используют символы в качестве ключей в хеше Ruby.
Какое преимущество перед использованием строки?
например:.
hash[:name]
против.
hash['name']
TL; DR:
Использование символов не только экономит время при выполнении сравнений, но и экономит память, поскольку они хранятся только один раз.
Рубиновые символы являются неизменяемыми (не могут быть изменены), что значительно упрощает поиск.
Краткий (ish) ответ:
Использование символов не только экономит время при выполнении сравнений, но и экономит память, поскольку они хранятся только один раз.
Символы в Ruby являются в основном "неизменяемыми строками".. это означает, что их нельзя изменить, и это означает, что один и тот же символ, на который ссылаются много раз по всему исходному коду, всегда сохраняется как та же сущность, например имеет тот же идентификатор объекта.
С другой стороны, строки изменчивы, их можно изменить в любое время. Это означает, что Ruby необходимо хранить каждую строку, которую вы упоминаете в исходном коде, в отдельном объекте, например если в вашем исходном коде несколько раз упоминается строка "имя", Ruby необходимо хранить их все в отдельных объектах String, поскольку в дальнейшем они могут измениться (это характер строки Ruby).
Если вы используете строку в качестве ключа Hash, Ruby необходимо оценить строку и просмотреть ее содержимое (и вычислить хеш-функцию для этого) и сравнить результат со значениями (хэшированными) ключей, которые уже хранятся в Hash..
Если вы используете символ в качестве ключа Hash, это подразумевает, что он неизменен, поэтому Ruby может просто выполнить сравнение (hash function of) object-id с (hashed) object-id ключей, которые уже хранятся в Хеш (намного быстрее)
Даунсайд: Каждый символ занимает слот в таблице символов интерпретатора Ruby, который никогда не освобождается. Символы никогда не собираются мусором. Так что angular случай - это когда у вас есть большое количество символов (например, автоматически сгенерированных). В этом случае вы должны оценить, как это влияет на размер вашего интерпретатора Ruby.
Примечания:
Если вы выполняете сравнение строк, Ruby может сравнивать символы только по их идентификаторам объектов, не оценивая их. Это намного быстрее, чем сравнение строк, которые необходимо оценить.
Если вы обращаетесь к хешу, Ruby всегда применяет хеш-функцию для вычисления "хеш-ключа" из любого ключа, который вы используете. Вы можете представить что-то вроде MD5-хеша. Затем Руби сравнивает эти "хешированные ключи" друг с другом.
Длинный ответ:
Причиной является эффективность с несколькими коэффициентами усиления над строкой:
O(n)
для строк и констант для символов.Кроме того, Ruby 1.9 представил упрощенный синтаксис только для хэша с символьными ключами (например, h.merge(foo: 42, bar: 6)
), а Ruby 2.0 аргументы ключевого слова которые работают только для ключей символов.
Примечания:
1) Вы можете быть удивлены, узнав, что Ruby рассматривает клавиши 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
в программе. До Ruby 2.2 было плохой идеей постоянно создавать новые Symbols
, которые никогда не использовались повторно, поскольку они останутся в глобальной таблице поиска Symbol навсегда. Ruby 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 или полезной нагрузке, например, через Rack), проще всего использовать строки везде.
Когда вы имеете дело с десятками из них, но они никогда не меняются (если они являются вашим "лексиконом" вашего бизнеса), мне нравится думать, что замораживание их может иметь значение. Я еще ничего не сделал, но думаю, что это будет близко к показателям символов.