Есть в стандартном классе Hash
такая
замечательная возможность — определить значение по-умолчанию,
которое будет выдаваться вместо nil
при обращении
по неизвестному ключу. Например:
h = Hash.new("") p h[:alpha]
выдаст именно пустую строку, а не пустое значение. Это само по себе
может быть весьма полезным, но возможности Hash.new()
этим не ограничиваются.
Гораздо интересней использование Hash.new()
с блоком, в котором можно сформировать произвольное значение. Простой (и, конечно,
надуманный) пример — пусть мы хотим хранить что-то типа адресной книги так, чтобы
по обращению с ключом типа String
получать записанные
опять же в хэш некие свойства (адрес, телефон и т.д.).
Если это делать «в лоб», то установка свойства будет выглядеть примерно так:
if book["Vasya Pupkin"] == nil book["Vasya Pupkin"] = {} end book["Vasya Pupkin"][:email] = "vasya@pupkin.name"
Нет, мы, конечно, можем воспользоваться «синтаксическим сахаром» и превратить первые три строки в одну...
book["Vasya Pupkin"] ||= {} book["Vasya Pupkin"][:email] = "vasya@pupkin.name"
Правда, выиграв немного в краткости, проигрываем (и сильно) в понятности... Получение свойства тоже будет не ахти:
if book["Vasya Pupkin"] book["Vasya Pupkin"][:email] else nil end
Ну, или какая-нибудь прелестная конструкция типа:
book["Vasya Pupkin"] && book["Vasya Pupkin"][:email]
И что самое главное — эта вот проверка на то, что для ключа задано правильное значение, будет постоянно забываться и выпадать в виде ошибки в самых непредвиденных местах.
Напрашивающийся вариант с инициализацией book = Hash.new({})
дает (в Ruby 1.8.7) вообще неожиданный результат:
book = Hash.new({}) book["Vasya Pupkin"][:email] = "vasya@pupkin.name" book["Masha Ivanova"][:phone] = "212-85-06" p book p book["Kolya Sidorov"]
Выдает следующее:
{} {:phone=>"212-85-06", :email=>"vasya@pupkin.name"}
И это, как ни странно, логично — просто значением по-умолчанию становится
не литерал {}
, а объект, изначально им инициализированный,
но в дальнейшем претерпевающий изменения.
И что делать? А вот что:
book = Hash.new do |hash, key| hash[key] = {} end
Очевидно, что внутри блока мы можем опять же воспользоваться вместо литерала
вызовом Hash.new()
с блоком и, таким образом, получить
хэш произвольной вложенности (ну, или более хитрую структуру, если нужно).
Комментариев нет:
Отправить комментарий