【问题标题】:Cloning a Hash in Ruby2 [duplicate]在Ruby2中克隆哈希[重复]
【发布时间】:2013-12-19 16:36:31
【问题描述】:

我试图克隆一个哈希,以制作原始哈希的新副本,但似乎当我在新哈希中设置一个值时,我对原始哈希有相同的效果。

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 副本吗?

提前致谢。

【问题讨论】:

标签: ruby


【解决方案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}}]}

【讨论】:

    【解决方案2】:

    哈希是键和值的集合,其中值是对对象的引用。复制散列时,会创建新散列,但会复制所有对象引用,因此您会得到包含相同值的新散列。这就是为什么这会起作用:

    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
    

    您可能应该为数组编写类似的内容。我也想过为整个可枚举模块编写它,但这可能会有点棘手。

    【讨论】:

      猜你喜欢
      • 2011-02-07
      • 2011-10-30
      • 1970-01-01
      • 1970-01-01
      • 2012-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-28
      相关资源
      最近更新 更多