рельсовый вложенный хеш со значениями по умолчанию - PullRequest
1 голос
/ 30 сентября 2019

Я хотел бы создать новый хэш со вложенными значениями по умолчанию. Я думал, что это должно быть похоже на

h = Hash.new(count: 0, rating: 0)

Так что я могу делать такие вещи, как

h['a'][:count] += 1
h['a'][:rating] += 1

и так далее. Но когда я пытаюсь сделать это в консоли, это выглядит так:

2.3.1 :046 > h = Hash.new(count: 0, rating: 0)
 => {} 
2.3.1 :047 > h["a"]
 => {:count=>0, :rating=>0} 
2.3.1 :048 > h["a"][:count]
 => 0 
2.3.1 :049 > h["a"][:count] += 1
 => 1 
2.3.1 :050 > h["b"][:count] += 1
 => 2
2.3.1 :051 > h
 => {}

Итак, мои вопросы:

  • Почему h["b"][:count] += 1 возвращает 2 ине 1?
  • почему ч пуст?

Заранее спасибо!

Ответы [ 2 ]

3 голосов
/ 30 сентября 2019

Документ для Hash :: new объясняет три способа инициализации хеша, и, в вашем случае, вы используете объект в конструкторе Hash:

ЕслиЕсли указан объект obj, этот единственный объект будет использоваться для всех значений по умолчанию.

Если вы хотите, чтобы каждый отсутствующий ключ создавал свой собственный объект, создайте хеш с блоком, например:

h = Hash.new { |h,k| h[k] = { count: 0, rating: 0 } }

Тогда:

2.6.3 :012 > h
 => {} 
2.6.3 :013 > h['a'][:count] = 5
 => 5 
2.6.3 :015 > h
 => {"a"=>{:count=>5, :rating=>0}} 
1 голос
/ 30 сентября 2019

Это поведение описано в документации Hash::new:

new → new_hash

new (obj) → new_hash

new {| hash, key |block} → new_hash

Возвращает новый пустой хеш. Если впоследствии к этому хешу обращается ключ, который не соответствует записи хеша, возвращаемое значение зависит от стиля нового, используемого для создания хеша. В первой форме доступ возвращает nil. Если указано obj , этот единственный объект будет использоваться для всех значений по умолчанию . Если указан блок, он будет вызываться с хеш-объектом иключ, и должен вернуть значение по умолчанию. Ответственность за сохранение значения в хэше лежит на блоке.

h = Hash.new("Go Fish")
h["a"] = 100
h["b"] = 200
h["a"]           #=> 100
h["c"]           #=> "Go Fish"
# The following alters the single default object
h["c"].upcase!   #=> "GO FISH"
h["d"]           #=> "GO FISH"
h.keys           #=> ["a", "b"]

# While this creates a new default object each time
h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
h["c"]           #=> "Go Fish: c"
h["c"].upcase!   #=> "GO FISH: C"
h["d"]           #=> "Go Fish: d"
h.keys           #=> ["c", "d"]

В вашем примере h["a"] и h["b"] оба возвращают один и тот же хеш-объект по умолчанию. Это означает, что если вы измените h["a"], h["b"] также изменится. Поскольку вы никогда не устанавливаете h["a"] или h["b"], хэш выглядит пустым.

Чтобы назначить новый хэш при доступе, вам нужно будет использовать синтаксис блока как , показанный luis.parravicini .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...