Ruby Hash:为不存在的元素创建默认值

unp*_*oss 3 ruby hash

在这里从这个答案中了解到这是可能的:

h = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }

h['bar'] # => {}
h['tar']['star']['par'] # => {}
Run Code Online (Sandbox Code Playgroud)

有人能解释它是如何工作的吗?

Dig*_*ora 12

哈希有一个叫做a的东西default_proc,它只是当你试图访问一个不存在的哈希键时Ruby运行的一个proc.此proc接收散列本身和目标键作为参数.

您可以随时设置哈希值default_proc.传递块参数Hash.new只是简单地允许您初始化哈希并将其设置为default_proc一步:

h = Hash.new
h.default_proc = proc{ |hash, key| hash[key] = 'foo' }

# The above is equivalent to:

h = Hash.new{ |hash, key| hash[key] = 'foo' }
Run Code Online (Sandbox Code Playgroud)

我们还可以通过调用访问哈希的默认proc h.default_proc.知道这一点,并且知道ampersand(&)允许作为普通参数传递的proc被视为块参数,我们现在可以解释这段代码是如何工作的:

cool_hash = Hash.new{ |h, k| h[k] = Hash.new(&h.default_proc) }
Run Code Online (Sandbox Code Playgroud)

Hash.new当我们尝试访问不存在的密钥时,将调用传递给的块.此块将接收哈希本身h,以及我们尝试访问的密钥k.我们通过设置h[k](即,我们尝试访问的密钥的值)来响应新哈希.在这个新哈希的构造函数中,我们传递"父"哈希default_proc,使用&符号强制它被解释为块参数.这相当于执行以下操作,达到无限深度:

cool_hash = Hash.new{ |h, k| h[k] = Hash.new{ |h, k| h[k] = Hash.new{ ... } } }
Run Code Online (Sandbox Code Playgroud)

最终的结果是我们试图访问的密钥被初始化为一个新的Hash,它本身会将任何"未找到"的密钥初始化为一个新的Hash,它本身会有相同的行为,等等.它一直是哈希.