我试图克隆一个哈希,以创建原始哈希的新副本,但似乎当我在新哈希中设置一个值时,我对原始哈希有相同的效果。
rr = Hash.new
command = "/usr/local/bin/aws route53 list-resource-record-sets --hosted-zone-id EXAMPLEID --max-items 1"
rr=JSON.parse(%x{#{command}})
puts rr
if rr["ResourceRecordSets"][0]["TTL"] != 60
new_rr = rr.clone
new_rr["ResourceRecordSets"][0]["TTL"] = 60
puts rr
puts new_rr
end
输出:
{"NextRecordType"=>"MX", "NextRecordName"=>"example.com.", "ResourceRecordSets"=>[{"ResourceRecords"=>[{"Value"=>"1.2.3.4"}], "Type"=>"A", "Name"=>"example.com.", "TTL"=>1800}], "MaxItems"=>"1", "IsTruncated"=>true}
{"NextRecordType"=>"MX", "NextRecordName"=>"example.com.", "ResourceRecordSets"=>[{"ResourceRecords"=>[{"Value"=>"1.2.3.4"}], "Type"=>"A", "Name"=>"example.com.", "TTL"=>60}], "MaxItems"=>"1", "IsTruncated"=>true}
{"NextRecordType"=>"MX", "NextRecordName"=>"example.com.", "ResourceRecordSets"=>[{"ResourceRecords"=>[{"Value"=>"1.2.3.4"}], "Type"=>"A", "Name"=>"example.com.", "TTL"=>60}], "MaxItems"=>"1", "IsTruncated"=>true}
我没有看到Ruby 2.0中记录的Hash.clone,我现在应该使用其他方法来创建Hash副本吗?
提前致谢。
答案 0 :(得分:4)
哈希是键和值的集合,其中值是对象的引用。复制哈希时,正在创建新哈希,但正在复制所有对象引用,因此您将获得包含相同值的新哈希。这就是为什么这会起作用的原因:
hash = {1 => 'Some string'} #Strings are mutable
hash2 = hash.clone
hash2[1] #=> 'Some string'
hash2[1].upcase! # modifying mutual object
hash[1] #=> 'SOME STRING; # so it appears modified on both hashes
hash2[1] = 'Other string' # changing reference on second hash to another object
hash[1] #=> 'SOME STRING' # original obejct has not been changed
hash2[2] = 'new value' # adding obejct to original hash
hash[2] #=> nil
如果要复制引用的对象,则需要执行深层复制。它作为deep_dup
方法添加到rails(activesupport gem)中。如果你没有使用rails并且不想安装gem,你可以像下面这样写:
class Hash
def deep_dup
Hash[map {|key, value| [key, value.respond_to?(:deep_dup) ? value.deep_dup : begin
value.dup
rescue
value
end]}]
end
end
hash = {1 => 'Some string'} #Strings are mutable
hash2 = hash.deep_dup
hash2[1] #=> 'Some string'
hash2[1].upcase! # modifying referenced object
hash2[1] #=> 'SOME STRING'
hash[1] #=> 'Some string; # now other hash point to original object's clone
您可能应该为数组编写类似的内容。我也想过为整个可枚举的模块编写它,但它可能会稍微复杂一点。
答案 1 :(得分:1)
制作大多数Ruby对象(包括字符串,数组,散列及其组合)的深层副本的最简单方法是使用Marshal
:
def deep_copy(obj)
Marshal.load(Marshal.dump(obj))
end
例如,
h = {a: 1, b: [:c, d: {e: 4}]} # => {:a=>1, :b=>[:c, {:d=>{:e=>4}}]}
hclone = h.clone
hdup = h.dup
hmarshal = deep_copy(h)
h[:b][1][:d][:e] = 5
h # => {:a=>1, :b=>[:c, {:d=>{:e=>5}}]}
hclone # => {:a=>1, :b=>[:c, {:d=>{:e=>5}}]}
hdup # => {:a=>1, :b=>[:c, {:d=>{:e=>5}}]}
hmarshal # => {:a=>1, :b=>[:c, {:d=>{:e=>4}}]}