2012-03-02 166 views
4

哈希初始化:红宝石哈希初始值设定

# this 
animals = Hash.new { [] } 
animals[:dogs] << :Scooby 
animals[:dogs] << :Scrappy 
animals[:dogs] << :DynoMutt 
animals[:squirrels] << :Rocket 
animals[:squirrels] << :Secret 
animals #=> {} 
# is not the same as this 
animals = Hash.new { |_animals, type| _animals[type] = [] } 
animals[:dogs] << :Scooby 
animals[:dogs] << :Scrappy 
animals[:dogs] << :DynoMutt 
animals[:squirrels] << :Rocket 
animals[:squirrels] << :Secret 
animals #=> {:squirrels=>[:Rocket, :Secret], :dogs=>[:Scooby, :Scrappy, :DynoMutt]} 

我看到有人张贴这些对另一个问题,但我不明白为什么会出现动物在第一种情况下的空白。如果我输入

animals[:dogs] 

我得到相应的数组。

+0

你可以链接到“另一个问题”? – 2012-03-02 00:22:07

+1

@Andrew:这看起来跟http://stackoverflow.com/q/9492889/479863一样,答案至少基本相同。 – 2012-03-02 00:26:19

+0

另一个问题是http://stackoverflow.com/questions/613985/common-ruby-idioms – 2012-03-02 00:58:09

回答

7

第一种形式指定返回未找到的键的默认值的块。这意味着当你调用animals[:dogs]时,散列中没有:dogs键,所以你的块被调用,animals[:dogs]对块的结果进行求值,即[]。然后会发生什么<< :Scooby:Scooby附加到该空列表,然后愉快地丢弃。

第二种形式指定当一个密钥被请求并且没有找到时,接收散列本身和未找到的密钥作为参数的块。这是第一个构造函数的稍微更强大的版本。区别在于你的块做什么。在此第二种形式中,您修改散列将[]与尚未找到的密钥相关联。所以现在它存储在散列内,并且<< :Scooby将在那里存储:Scooby。进一步调用:dog将不会触发该块,因为现在:dog存在于哈希中。

+1

更多信息在这里:http://www.ruby-doc.org/core-1.9.3/Hash.html – 2012-03-02 00:23:41

0

第一次失败的原因,第二次失败的原因是因为传入Hash.new的块。

此块用于定义在访问尚不存在的密钥时返回的默认类型。在第一个示例中,没有入口初始化程序,因此每个新密钥都会返回{}或空的Hash。哈希没有方法<<,所以它什么都不返回。

第二种情况正常工作,因为条目初始值设定项被定义为空的Array。因此,在这种情况下,当您第一次访问animals[:dogs]时,它将返回[]空的Array而不是{}空的Hash。数组确实有一个名为<<的方法,因此它可以成功工作,并将该符号铲入指定键的数组中。

希望这会清除它。

+0

不,第二种情况下工作,因为该块将新密钥添加到散列。在第一种情况下'''从不在哈希上使用,它总是用在数组上。该块没有定义返回*类型*,它定义了返回*值*。 – 2012-03-02 00:31:24

+0

实际上,在第一种情况下,您不会因此而获得{}。你得到'[]',因为这是你从默认值块得到的结果。如果你*得到了'{}',那么调用''''会抛出一个'NoMethodError',而不会返回任何东西。 – 2012-03-02 00:31:56

3

在第一种情况下,密钥不存在时返回的默认值为[]。各种语句然后成功地将各种狗和松鼠添加到返回的数组中。

然而,在任何时候为:dogs:squirrels.

有史以来在第二种情况中的一个关键,块确实店新值回用关键的哈希条目。

这里有一件有趣的事情是你如何在第一种情况下继续获得新的空数组。答案是:你没有通过[]作为参数,而是作为一个块。这是可执行的,它被保存为一个proc。每次找不到密钥时,proc会再次运行并生成一个新的[]

您可以在操作看到这一点,注意不同的对象ID值:

irb > t = Hash.new { [] } 
=> {} 
irb > t[:a].object_id 
=> 2149202180 
irb > t[:a].object_id 
=> 2149192500