ruby hash autovivification(facets)

art*_*ave 8 ruby

这是一个聪明的技巧,在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
Run Code Online (Sandbox Code Playgroud)

虽然它有效(当然),但我发现我无法弄清楚这两个衬垫是如何做到的.

leet被置为默认值.所以,然后只是h['new_key']以某种方式访问它,并创建'new_key' => {}

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

mik*_*kej 18

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

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


Pet*_*net 8

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

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

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

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