就哈希默认值而言,当您将块作为默认值传递时,此实例中会发生什么,例如:
hash = Hash.new {|hash, key| hash[key] = [] }
我运行了以下代码:
hash[:one] << "uno"
hash[:two] << "dos"
hash[:three]
hash[:four]
hash #returns the hash
,输出为:
{:two=>["dos"], :three=>[], :four=>[], :one=>["uno"]}
有人可以用简单的英语解释一下会发生什么吗?
答案 0 :(得分:2)
目标
让我们从这里开始:
h = {}
h[:a] = [] unless h.key?(:a)
h[:a] << 7
我们创建一个空哈希h
。此哈希的每个值都是一个值数组。我们希望将7
附加到数组:a
的值。如果h
已经有一个密钥:a
,我们会有类似h[:a] #=> [3,5]
的内容,因此我们只需将7
附加到该数组:
h[:a] << 7 #=> [3,5,7]
但是,如果h
没有密钥:a
(所以h[:a] #=> nil
),我们首先需要将h[:a]
设置为空数组。因此需要:
h[:a] = [] unless h.key?(:a)
如果h
无法拥有值为:a
的密钥nil
(换句话说,如果没有值是nil
),我们可以改为:
h[:a] = [] unless h[:a]
类似Ruby的技巧
我们可以通过几种方式使其更像Ruby。第一个是:
h = {}
(h[:a] ||= []) << 7 #=> [7]
h #=> {:a=>[7]}
(h[:a] ||= []) << 9 #=> [7, 9]
h #=> {:a=>[7, 9]}
当Ruby看到:
h[:a] ||= []
她做的第一件事就是把它转换成:
h[:a] = h[:a] || []
步骤如下:
(h[:a] = h[:a] || []) << 7
#=> (h[:a] = nil || []) << 7
#=> (h[:a] = []) << 7
#=> h[:a] << 7
h[:a] #=> [7]
(h[:a] = h[:a] || []) << 9
#=> (h[:a] = [7] || []) << 9
#=> (h[:a] = [7]) << 9
#=> h[:a] << 9
h[:a] #=> [7,9]
类似Ruby的默认值
第二种类似Ruby的方法与第一种方法相同,但是通过为哈希定义默认值来实现。如果哈希h
没有键k
,则h[k]
将返回默认值。这也改变了哈希吗?我们暂时解决这个问题。
Hash::new的文档解释了有两种方法可以定义默认值。
错误的默认值
第一个,为了使默认值为空数组,是:
h = Hash.new([]) #=> {}
所以,如果我们现在写:
h[:a] #=> []
返回默认值([]
)。它不会改变哈希:
h #=> {}
我们可能想写:
h[:a] << 7
#=> [] << 7 => [7]
(h[:a]
返回默认值,因为没有键:a
。)如您所见,这不会改变哈希值,它只会返回一个未附加的数组[7]
什么都是垃圾收集。
现在让我们试试这个:
(h[:a] = h[:a]) << 7
#=> (h[:a] = []) << 7 => [7]
h #=> {:a=>[7]}
(h[:a] = h[:a]) << 9
#=> (h[:a] = [7]) << 9 => [7, 9]
h #=> {:a=>[7, 9]}
到目前为止,这么好,但是有一个问题:
(h[:b] = h[:b]) << 11 #=> [7, 9, 11]
h #=> {:a=>[7, 9, 11], :b=>[7, 9, 11]}
(h[:b] = h[:b]) << 13 #=> [7, 9, 11, 13]
h #=> {:a=>[7, 9, 11, 13], :b=>[7, 9, 11, 13]}
如您所见,只有一个默认空数组。
正确的默认值
幸运的是,还有另一种指定默认数组的方法:给Hash#new
一个块。 (我们终于达到了问题的重点。)
如果散列h
没有密钥k
,h[k]
将调用该块。该块有两个块变量h
和k
。您可以在块中执行您想要的任何内容。例如:
@a = 3
h = Hash.new { |h,k| @a = 7 }
h[:a] #=> 7
h #=> {}
@a #=> 7
现在我非常怀疑你是否想要这样做,但你可以。对于当前问题,您希望新键的值为空数组:
h = Hash.new { |h,k| h[k] = [] }
(小心。如果我们执行:
puts h[:a]
#=> []
然后我们
h #=> { :a=>[] }
)
所以:
h[:a] << 7
首先调用该块,因为h
没有键k
,所以我们现在有:
{ :a=>[] }[:a] << 7
h #=> { :a=>[7] }
现在我们执行:
h[:a] << 9
h #=> {:a=>[7, 9]}
未调用该块,因为h
有一个键:a
。
关于它。有问题吗?