В соответствии с спецификацией строки, которые используются в качестве ключа к хэшу, дублируются и заморожены. Другие изменчивые объекты, похоже, не имеют такого особого рассмотрения. Например, с помощью ключа массива возможно следующее.
a = [0]
h = {a => :a}
h.keys.first[0] = 1
h # => {[1] => :a}
h[[1]] # => nil
h.rehash
h[[1]] # => :a
С другой стороны, подобная вещь не может быть выполнена с помощью строкового ключа.
s = "a"
h = {s => :s}
h.keys.first.upcase! # => RuntimeError: can't modify frozen String
Почему строка должна отличаться от других изменяемых объектов, когда дело доходит до хеш-ключа? Существует ли какой-либо прецедент, когда эта спецификация становится полезной? Какие другие последствия имеет эта спецификация?
У меня на самом деле есть прецедент, когда отсутствие такой специальной спецификации о строках может быть полезно. То есть, я прочитал с
yaml
gem вручную написанный файл YAML, который описывает хэш. ключи могут быть строками, и я хотел бы разрешить нечувствительность к регистру в исходном файле YAML. Когда я читаю файл, я могу получить хэш вот так:
h = {"foo" => :foo, "Bar" => :bar, "BAZ" => :baz}
И я хочу нормализовать ключи для нижнего регистра, чтобы получить это:
h = {"foo" => :foo, "Bar" => :bar, "BAZ" => :baz}
выполнив что-то вроде этого:
h.keys.each(&:downcase!)
но возвращает ошибку по причине, описанной выше.