在 Ruby 中设置哈希等于另一个哈希
Posted
技术标签:
【中文标题】在 Ruby 中设置哈希等于另一个哈希【英文标题】:Setting hash equal to another hash in Ruby 【发布时间】:2012-07-15 17:53:17 【问题描述】:我想跟踪一些任意命名的字符串的计数,然后将计数重置为零。我的想法是做以下事情:
reset_hash="string1"=>0,"string2"=>0,"string3"=>0
=> "string1"=>0, "string2"=>0, "string3"=>0
new_hash = reset_hash
=> "string1"=>0, "string2"=>0, "string3"=>0
new_hash["string1"]=1
new_hash["string3"]=1
new_hash
=> "string1"=>1, "string2"=>0, "string3"=>1
...
现在我想将 new_hash 重置为 reset_hash:
new_hash = reset_hash
=> "string1"=>1, "string2"=>0, "string3"=>1
reset_hash
=> "string1"=>1, "string2"=>0, "string3"=>1
这里发生了什么?看来reset_hash实际上已经设置为new_hash,这与我想要的相反。如何实现所需的行为?
【问题讨论】:
【参考方案1】:您正在修改单个哈希。
两个变量都引用同一个哈希。当您更改哈希中的项目时,两个引用都会反映该更改 - 因为它是相同的哈希实例。
也许您想先复制哈希?如果你这样做了,并且你有一个包含复杂对象的哈希,你还需要研究浅拷贝和深拷贝/克隆。
【讨论】:
我以为我在复制哈希。那么我该如何正确地做到这一点呢? 您正在将 reference 复制到散列;您需要使用clone
(docs),注意注意事项。有很多方法可以进行深度克隆,包括仅对对象进行编组/解组。【参考方案2】:
您需要使用克隆来制作副本。
见https://***.com/a/4157438/1118101
否则,您只会创建 2 个指向同一个哈希的“指针”,而不是复制内容。
然后使用替换将克隆的内容复制回您现有的哈希中。
【讨论】:
【参考方案3】:当你有一个指向一个对象的变量时,你实际上只是有一个对该对象的引用。如果 a 和 b 都指向哈希 1=>3, "foo" => 54,则更改 a 或 b 将更改另一个。
但是,您可以结合使用两种方法来制作您想要的东西。
哈希的默认值:
new_hash = Hash.new(0)
这为未使用的值提供了默认值 0:
new_hash["eggs"] # -> 0
然后您可以添加计数:
new_hash["string1"] += 1 # => 1
完成后打电话
new_hash.clear # =>
并且您的哈希值将被重置,但新访问仍将默认为 0。
请注意,如果您将默认值设置为数字以外的对象类型,您可能会因为上面提到的整个参考问题而改变事物。
irb(main):031:0> b = Hash.new("Foo") #=>
irb(main):032:0> b[3] #=> "Foo"
irb(main):033:0> b[33] #=> "Foo"
irb(main):034:0> b[33].upcase! #=> "FOO"
irb(main):035:0> b[3] # => "FOO"
要解决这个问题,您可以将一个块传递给您的哈希:
h = Hash.new |hash, key| hash[key] = "new default value"
这每次都会在 key 处创建一个新对象,因此对一个对象的更改不会产生涟漪:
d = Hash.new |hash,key| hash[key] = "string" #=>
d[3] # => "string"
d[3].upcase! #=> "STRING"
d[5] #=> "string"
【讨论】:
【参考方案4】:正如其他人提到的,您必须使用clone。您的任务应如下所示:
reset_hash="string1"=>0,"string2"=>0,"string3"=>0
new_hash = reset_hash.clone
new_hash["string1"]=1
new_hash["string3"]=1
new_hash
new_hash = reset_hash.clone
reset_hash
【讨论】:
以上是关于在 Ruby 中设置哈希等于另一个哈希的主要内容,如果未能解决你的问题,请参考以下文章