哈希初始值设定项:
# 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 :(得分:7)
第一种形式指定为未找到的键返回默认值的块。这意味着当您调用animals[:dogs]
时,哈希中没有:dogs
键,因此您的块会被调用,而animals[:dogs]
会计算块的结果,即[]
。然后会发生<< :Scooby
将:Scooby
附加到该空列表中,然后很高兴地将其丢弃。
第二种形式指定了当请求密钥并且未找到密钥时,作为参数接收散列本身和尚未找到的密钥的块。它是第一个构造函数的稍微强大的版本。不同之处在于您的块所做的事情。在第二种形式中,您修改哈希,以将[]
与尚未找到的密钥相关联。所以现在它存储在哈希中,<< :Scooby
将存储:Scooby
。对:dog
的进一步调用不会触发阻止,因为现在哈希中存在:dog
。
答案 1 :(得分:3)
在第一种情况下,当密钥不存在时返回的默认值是[]
。然后各种语句成功地将各种狗和松鼠添加到返回的数组中。
但是,从来没有为:dogs
或:squirrels.
在第二种情况下,块使用密钥将新值存储回哈希条目。
这里有一点有趣的是你在第一种情况下如何继续获得一个新的空数组。答案是:您没有将[]
作为参数传递,而是作为块传递。这是可执行文件,它被保存为proc。每次找不到密钥时,proc都会再次运行并生成新的[]
。
您可以在操作中看到这一点,请注意不同的对象ID值:
irb > t = Hash.new { [] }
=> {}
irb > t[:a].object_id
=> 2149202180
irb > t[:a].object_id
=> 2149192500
答案 2 :(得分:0)
第一个失败而第二个失败的原因是因为传递给Hash.new的块。
此块用于定义访问尚不存在的键时返回的默认类型。在第一个示例中,没有条目初始化程序,因此每个新密钥返回{}
或空Hash
。哈希没有方法<<
,所以它什么都不返回。
第二种情况正常,因为条目初始值设定项被定义为空Array
。因此,在这种情况下,当您第一次访问animals[:dogs]
时,它会返回[]
空Array
而不是{}
空Hash
。 Array确实有一个名为<<
的方法,因此它可以成功运行并将符号铲入指定键的数组中。
希望这可以解决它。