我试图通过使用另一个具有默认值的哈希来初始化 ruby 中的哈希。我想要一个深副本,但我似乎只得到一个浅副本。
这是一个例子:
DEFAULT_HASH = { a: 0, b: 1 }.freeze
my_hash = DEFAULT_HASH.dup
my_hash[:a] = 4
Run Code Online (Sandbox Code Playgroud)
现在“my_hash”和 DEFAULT_HASH 中的 a 值是 4。我只希望哈希中的值发生变化。
我也尝试过其他方法:
my_hash = {}.merge DEFAULT_HASH
Run Code Online (Sandbox Code Playgroud)
和
my_hash.merge! DEFAULT_HASH
Run Code Online (Sandbox Code Playgroud)
所有这些都会产生相同的效果。实现这种初始化的最佳方法是什么?我还使用嵌套哈希,这增加了一点复杂性。
即我的 DEFAULT_HASH 看起来像:
DEFAULT_HASH = { a:{a:1, b:2}, b:{a:2, b:1} }
Run Code Online (Sandbox Code Playgroud)
这会影响如何做到这一点吗?
编辑:嵌套哈希案例
DEFAULT_HASH = { a:{a:1, b:2}, b:{a:2, b:1} }
=> {:a=>{:a=>1, :b=>2}, :b=>{:a=>2, :b=>1}}
a=DEFAULT_HASH.dup
=> {:a=>{:a=>1, :b=>2}, :b=>{:a=>2, :b=>1}}
a[:b][:a]=12
=> 12
DEFAULT_HASH
=> {:a=>{:a=>1, :b=>2}, :b=>{:a=>12, :b=>1}}
Run Code Online (Sandbox Code Playgroud)
对于@pjs 的观点,Hash#dup将为哈希的顶层“做正确的事情”。然而,对于嵌套哈希,它仍然失败。
如果您愿意使用 gem,请考虑使用deep_enumerable,这是我为此目的(以及其他目的)编写的 gem。
DEFAULT_HASH = { a:{a:1, b:2}, b:{a:2, b:1} }
dupped = DEFAULT_HASH.dup
dupped[:a][:a] = 'updated'
puts "dupped: #{dupped.inspect}"
puts "DEFAULT_HASH: #{DEFAULT_HASH.inspect}"
require 'deep_enumerable'
DEFAULT_HASH = { a:{a:1, b:2}, b:{a:2, b:1} }
deep_dupped = DEFAULT_HASH.deep_dup
deep_dupped[:a][:a] = 'updated'
puts "deep_dupped: #{deep_dupped.inspect}"
puts "DEFAULT_HASH: #{DEFAULT_HASH.inspect}"
Run Code Online (Sandbox Code Playgroud)
输出:
dupped: {:a=>{:a=>"updated", :b=>2}, :b=>{:a=>2, :b=>1}}
DEFAULT_HASH: {:a=>{:a=>"updated", :b=>2}, :b=>{:a=>2, :b=>1}}
deep_dupped: {:a=>{:a=>"updated", :b=>2}, :b=>{:a=>2, :b=>1}}
DEFAULT_HASH: {:a=>{:a=>1, :b=>2}, :b=>{:a=>2, :b=>1}}
Run Code Online (Sandbox Code Playgroud)
或者,您可以尝试以下方法:
def deep_dup(h)
Hash[h.map{|k, v| [k,
if v.is_a?(Hash)
deep_dup(v)
else
v.dup rescue v
end
]}]
end
Run Code Online (Sandbox Code Playgroud)
请注意,最后一个函数远没有经过充分的测试deep_enumerable。