ruby hash autovivification(facets)

这是一个聪明的技巧,在ruby中启用哈希自动生成(取自facet):

# 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' => {}

现在,我希望h['new_key']返回默认值对象而不是评估它。 也就是说, 'new_key' => {}不会自动创建。 那么leet实际上是如何被调用的呢? 特别是有两个参数?

Hash的标准新方法接受块。 如果尝试访问Hash中不存在的密钥,则调用此块。 该块传递Hash本身和请求的密钥(两个参数),并应返回应为所请求的密钥返回的值。

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

值得注意的是,此代码可以按如下方式制作成一行:

 def self.autonew(*args) new(*args){|hsh, key| hsh[key] = Hash.new(&hsh.default_proc) } end 

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

我在博客上谈到了类似的案例 。

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

如果你寻找一些尚不存在的东西,你可以得到一个零值(或者你喜欢的另一个值或一个例外),而不用通过观察来创建任何东西。 它也可以附加到数组的末尾。

您可以选择为整数键自动生成哈希值或数组(但对于整个结构只需一次)。