【问题标题】:Ruby Hash InitializersRuby 哈希初始化器
【发布时间】:2012-03-20 12:54:39
【问题描述】:

哈希初始化器:

# 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]

我得到了合适的数组。

【问题讨论】:

标签: ruby hash autovivification


【解决方案1】:

第一种形式指定为未找到的键返回默认值的块。这意味着当您调用animals[:dogs] 时,哈希中没有:dogs 键,因此您的块被调用并且animals[:dogs] 评估为您的块的结果,即[]。然后发生的事情是&lt;&lt; :Scooby:Scooby 附加到那个空列表,然后很高兴将其丢弃。

第二种形式指定块,当请求密钥但未找到时,接收作为参数的散列本身和尚未找到的密钥。它是第一个构造函数的稍微强大的版本。不同之处在于您的块的作用。在第二种形式中,您修改哈希以将[] 与尚未找到的密钥相关联。所以现在它存储在哈希中,&lt;&lt; :Scooby 将在那里存储:Scooby。进一步调用:dog 不会触发区块,因为现在:dog 存在于哈希中。

【讨论】:

    【解决方案2】:

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

    但是,从来没有为:dogs:squirrels. 创建密钥

    在第二种情况下,块确实使用键将新值存储回哈希条目。

    这里有些有趣的事情是,在第一种情况下,您如何不断地返回一个新的空数组。答案是:您没有将[] 作为参数传递,而是作为块传递。这是可执行的,它被保存为一个过程。每次找不到密钥时,proc 都会再次运行并生成一个新的[]

    你可以在操作中看到这个,注意不同的对象id值:

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

    【讨论】:

      【解决方案3】:

      第一个失败而第二个没有的原因是传递给 Hash.new 的块。

      此块用于定义当您访问一个尚不存在的键时返回的默认类型。在第一个示例中,没有条目初始化程序,因此每个新键都返回{},或者一个空的Hash。 Hash 没有方法&lt;&lt;,所以它什么也不返回。

      第二种情况正常工作,因为入口初始化程序被定义为空Array。因此,在这种情况下,当您第一次访问animals[:dogs] 时,它会返回[] 一个空的Array,而不是{} 一个空的Hash。 Array 确实有一个名为&lt;&lt; 的方法,因此它可以成功运行并将符号铲到指定键处的数组中。

      希望这能解决问题。

      【讨论】:

      • 不,第二种情况有效,因为该块将新密钥添加到哈希中。在第一种情况下,&lt;&lt; 永远不会用于哈希,它总是用于数组。该块没有定义返回type,它定义了返回value
      • 实际上,在第一种情况下,您不会得到 {} 结果。你得到[],因为这是你从默认值块中得到的结果。如果你确实得到了{},那么在它上面调用&lt;&lt;会抛出一个NoMethodError而不是什么都不返回。
      猜你喜欢
      • 1970-01-01
      • 2010-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-24
      • 2016-02-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多