此问题在此处已有答案:
Strange, unexpected behavior (disappearing/changing values) when using Hash default value, e.g. Hash.new([])(4个答案)
22天前关闭
为什么尝试存储Hash.new({})
的嵌套值会这样工作?实际上在幕后发生了什么?它的用例是什么?
当创建具有默认值{}的哈希时,
a = Hash.new({})
=> {}
a.default
=> {}
字符串
查询一个不存在的键将返回一个空的哈希值
a[:foo]
=> {}
型
然而,当试图将值分配给尚不存在的键时,
a[:foo][:bar] = 'baz'
=> "baz"
型
散列仍然显示为空
a
=> {}
型
然而,获取父键将返回嵌套的散列。
a[:foo]
=> {:bar=>"baz"}
型
更令人困惑的是,这个新哈希现在已经成为父哈希的默认值
a.default
=> {:bar=>"baz"}
型
使得查询不存在键将返回该值
a[:biz]
=> {:bar=>"baz"}
型
这可以通过做
a[:foo] = {} unless a.key? :foo
a[:foo][:bar] = 'baz'
a
=> {:foo=>{:bar=>"baz"}}
型
其他类似的问题也建议使用a = Hash.new { |h,k| h[k] = Hash.new(&h.default_proc) }
,它用于存储新的密钥,但也会为获取操作创建空的哈希值,例如。
a[:baz] == 2
a
=> {:baz=>{}}
型
除了编写方法之外,是否有其他方法可以在存储值时获得哈希以创建嵌套哈希,而在获取值时则不需要?
2条答案
按热度按时间icomxhvb1#
记住,在Ruby 1中,你存储的是一个默认的 object reference,而不是一个 cloned 的默认值。即使这不是你的意图,你也要求任何缺少的键的默认值都是 same object。对于像
Hash.new(0)
这样的简单值,当一个新值被赋值时,默认值不会改变,它是 replaced,但是对于嵌套的hash,你显式地改变了值。你想要的是最小化地表达为:
字符串
如果你对为什么事物最终会这样混合感到困惑,请检查
object_id
,它告诉你给定对象的“身份”。请考虑:
型
在这里你可以看到每个“槽”是独立的。
这些自动示例化模型的一个缺点是,正如你所指出的,它会创建你可能不需要的条目。为了避免这种情况,你需要更小心地处理,如:
型
1 JavaScript、Python和其他语言也表现出这种行为,至少对于非原语类型来说是这样。
ac1kyiln2#
如果你不想为fetch操作创建空哈希值,你可以使用#freeze来保护默认值不被意外修改。
字符串