Ruby哈希自动创建(facets)

8
这里有一个聪明的技巧可以在 Ruby 中启用哈希自动成型(来自 facets):
  # File lib/core/facets/hash/autonew.rb, line 19
  def self.autonew(*args)
    leet = lambda { |hsh, key| hsh[key] = new( &leet ) }
    new(*args,&leet)
  end

尽管它(当然)能工作,但我发现我无法弄清楚这两行代码实际上是如何实现的,这让我感到非常沮丧。 leet被设置为默认值。 因此,只需访问h ['new_key'],就会将其提起并创建 'new_key' => {}。
现在,我期望'new_key'=>{}只返回默认值对象,而不是对其进行评估。 也就是说,'new_key' => {} 不会自动创建。那么,leet 实际上是如何被调用的呢?特别是带有两个参数?
3个回答

18

标准 哈希的新方法 接受一个块。当尝试访问哈希中不存在的键时,调用该块。该块传递哈希本身和被请求的键(这两个参数),应返回应为所请求键返回的值。

您会注意到 leet lambda 做了两件事情。它返回一个新的哈希表,其中leet 本身作为处理默认值的块。这种行为允许对任意深度的哈希表进行自动创建。它还将此新哈希表分配给 hsh[key],以便下次请求相同的键时,您将得到现有的哈希表,而不是创建一个新的。


1
确实是这样。特别是,这会教我再也不要参考RubyBook(随标准Ruby Windows发布的书),因为它没有提到关于块和new的微不足道的事实。 - artemave

8
值得注意的是,这段代码可以转化为一行代码,如下所示:
def self.autonew(*args)
  new(*args){|hsh, key| hsh[key] = Hash.new(&hsh.default_proc) }
end

调用 Hash#default_proc 会返回用于创建父对象的 proc,因此我们在这里有一个很好的递归设置。

我在我的博客中谈到了一个类似的情况similar case


0

或者,你可以考虑使用我的xkeys gem。这是一个模块,你可以用它来扩展数组或哈希以便于嵌套访问。

如果你查找的东西不存在,你会得到一个nil值(或者其他值,或者如果你喜欢的话,会抛出异常),而不会创建任何东西。它还可以追加到数组的末尾。

你可以选择自动创建哈希或数组来存储整数键(但只对整个结构创建一次)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接