ruby中哈希数据类型中的“默认值是同一个对象”

时间:2015-11-11 06:12:00

标签: ruby hash

我是Ruby的新手并且正在运行Ruby Koans。在Ruby Koans的about_hashes.rb文件中,有一个为散列分配默认值的示例。

hash = Hash.new([])
hash[:one] << "uno"
hash[:two] << "dos"

puts hash[:one]  # this is  ["uno", "dos"]

这里hash[:one]&amp; hash[:two]或任何类似hash[:three]的键(非现有键)都具有值[“uno”和“dos”]我不明白“&lt;&lt;”在这里使用。此外,当我尝试提取键和&amp;哈希值,或打印键/值,它是空的。

puts (hash.values.size)  # size is 0 here
puts (hash.keys.size)    # size is 0 
puts hash.values         # nothing gets printed
puts hash.keys           #nothing gets printed.

那么这里发生了什么?存储的值在哪里,如果它们没有作为键或值存储在散列中。

在下一个例子中,当Hash定义为

hash = Hash.new {|hash, key| hash[key] = [] }
hash[:one] << "uno"
hash[:two] << "dos"
puts hash[:one]  #this is "uno"
puts hash[:two] #this is "dos"
puts hash[:three] # this is undefined.

我想在第二个例子中,hash正在使用空白数组初始化所有键。因此当“&lt;&lt;”时,“uno”会被附加到空数组中使用此运算符?我对这两个例子感到困惑。我不知道他们俩发生了什么。我也无法在谷歌中找到关于这个例子的更多信息。如果有人可以帮我解释这两个例子,那将会很有帮助。提前致谢

2 个答案:

答案 0 :(得分:4)

<强> hash = Hash.new([])

此语句创建一个空哈希,其默认值为空数组。如果hash没有密钥k,则hash[k]会返回默认值[]。这很重要:只需返回默认值修改哈希值。

当你写:

hash[:one] << "uno" #=> ["uno"]

hash有一个键:one之前,hash[:one]被默认值替换,所以我们有:

[] << "uno" #=> ["uno"]

解释了为什么hash没有改变:

hash #=> {}

现在写:

hash[:two] << "dos" #=> ["uno", "dos"]
hash                #=> {}

为了了解我们得到此结果的原因,请按以下步骤重写以上内容:

hash = Hash.new([])       #=> {} 
hash.default              #=> [] 
hash.default.object_id    #=> 70209931469620 
a = (hash[:one] << "uno") #=> ["uno"] 
a.object_id               #=> 70209931469620 
hash.default              #=> ["uno"]  
b = (hash[:two] << "dos") #=> ["uno", "dos"] 
b.object_id               #=> 70209931469620 
hash.default              #=> ["uno", "dos"]  

因此,您可以看到object_id70209931469620的默认数组是&#34; uno&#34;和&#34; dos&#34;附加。

如果我们写了:

hash[:one] = hash[:one] << "uno"
  #=> hash[:one] = [] << "uno" => ["uno"]
hash #=> { :one=>"uno" }

我们得到了我们希望的东西,但不是那么快:

hash[:two] = hash[:two] << "dos"
  #=> ["uno", "dos"] 
hash
  #=> {:one=>["uno", "dos"], :two=>["uno", "dos"]} 

仍然不是我们想要的,因为两个键的值都是相同的数组。

<强> hash = Hash.new {|hash, key| hash[key] = [] }

hash没有密钥key时,此语句会导致执行该块。此 通过添加键值对 1 来更改哈希值。

现在:

hash[:one] << "uno"

导致阻止:

{ |h,k| h[k] = [] }

进行作业:

hash[:one] = []

之后:

hash[:one] << "uno"

"uno"附加到一个空数组,该数组是键:one的值,我们可以验证:

hash #=> { :one=>"uno" }

这与写作具有相同的效果:

hash[:one] = (hash[:one] || []) << "uno"

(hash[:one] ||= []) << "uno"的扩展版本),当没有默认值时。

类似地,

hash[:two] << "dos" #=> ["dos"] 
hash #=> {:one=>["uno"], :two=>["dos"]}

这通常是我们想要的结果。

1但是,块不需要更改哈希值。该块可以包含任何代码,例如{ puts "Have a nice day" }

答案 1 :(得分:3)

hash = Hash.new(INITIAL_VALUE)是用于创建哈希的语法,具有默认值。默认值是整个散列本身的“属性”,当访问不存在的密钥时,它将被返回。

所以,在你的第一个例子中:

hash = Hash.new([]) # return a reference to an empty array for unknown keys

与:

相同
initial = []
hash = Hash.new(initial)

因此,当你打电话:

hash[:one] << "uno"

您实际上致电hash[:one],返回initial,然后在其上调用#<<方法。换句话说,这些后续调用与:

相同
initial << "uno"
initial << "dos"

我想,现在很清楚,为什么所有人都在分享相同的价值。哈希本身仍然是空的(在上面的任何调用中,正在使用initial。)看:

hash.merge! { one: "uno", three: "tres" }
hash[:one] # defined, since merge above
#⇒ "uno"
hash[:two] # undefined, initial will be returned
#⇒ []
hash[:two] << 'dos'
hash[:two] # defined, but defined as a reference to initial
#⇒ ["dos"]
hash[:two] = 'zwei' # redefined
#⇒ "zwei"
hash[:four] # undefined, initial
#⇒ ["dos"]

希望它有所帮助。