这个问题已经在这里有一个答案:
- 奇怪的,意想不到的行为使用Hash默认值,例如Hash.new([])时(消失/变更值) 4个答案
我试图在IRB的几行代码,然后我发现我不能修改返回从哈希默认值的新数组。 下面是一个IRB会话显示更多的细节我的情况:
a = Hash.new { Array.new }
#=> {}
a[2]
#=> []
a[2].push '2'
#=> ["2"]
a[2]
#=> []
a[2] = []
#=> []
a[2].push '2'
#=> ["2"]
a
#=> {2=>["2"]}
a[2].push '2'
#=> ["2", "2"]
a
#=> {2=>["2", "2"]}
为什么我不能修改一个不存在的键的默认值?
块形式的Hash#new
这样使用:
b = Hash.new {|hash, key| hash[key] = Array.new}
#=> {}
b[2]
#=> []
b[2].push('2')
#=> ["2"]
b[2]
#=> ["2"]
b[3]
#=> []
b[3].push('3')
#=> ["3"]
b[3]
#=> ["3"]
见Hash.new {|hash, key| block } → new_hash
Hash.new {|hash, key| block } → new_hash
。 它说:
如果指定了块,它将与哈希对象和重点调用,应返回默认值。 它是块的,如果需要存储在哈希值的责任。
这意味着你必须创建一个存储您传递到哈希当你创建一个新的或更新现有的值键的值的块。 因为,你的哈希定义并不存储它:
a = Hash.new { Array.new }
你将失去价值,不管你有多少次这样做:
a[2].push '2' #=> ["2"]
p a #=> {}
你在做什么是你再定义与默认值的关键:
a[2] = []
然后你推值:
a[2].push #=> ["2"]
p a #=> {2 => ["2"]}
这种情况,有您可以在其中定义块是这样一种方式:
a = Hash.new { |h, k| h[k] = Array.new }
要么:
a = Hash.new { |h, k| h[k] = [] }
如果你看到上面的块,它说:密钥的缺省值将是一个空数组,如果任何物体推到它:
a[2].push '2' #=> ["2"]
它将存储该对象到该数组:
p a #=> {2=>["2"]}
有使用没有问题:
a = Hash.new { Array.new }
如果我执行a[2]
将返回[]
因为这是默认值。 它只是告诉我它是什么,仅此而已。
因为默认的被给定为一个块,默认值是一个新的空数组每次a[x]
被调用。 要了解的重要一点是,它仅仅是一个空的数组,而不是依赖于哈希a
以任何方式。 也就是说, a[2]
只回答了“什么是默认值?” 它不会对它做任何事。 (如图所示在其他的答案,如果块被写入不同,奇妙的各种东西可以返回默认值之前完成。)
需要注意的是Hash.new { Array.new }
, Hash.new { [] }
和Hash.new { |h,k| Array.new }
Hash.new { |h,k| Array.new }
都是等价的。
为了将密钥添加2
到a
, a[2]
必须是一个左值。 你必须在你随后的例子:
a[2] = []
但如果这样做,有没有点有一个默认值。 你想要做的是什么设置a[2]
等于默认值:
a[2] = a[2]
(注意,如果,如在这种情况下,块的返回值不依赖于所述键,上面的行相当于:
a[2] = a[123456]
只要没有钥匙123456
)。
其将所述关键值对2=>[]
到散列,所以现在
a[2].push 2
a[2].push 3
a #=> {2=>[2, 3]}
它更有意义,但是,要做到这一步:
a[2] = a[2].push 2
如果a
不具有键2
, a[2]
上的平等将等于空数组的缺省值的右侧, 2
将被推到其上和用于键的值2
将被设置为等于[2]
如果a
已经有一个键2
,说a[2] = [3,4,5]
a[2]
右边将[3,4,5]
2
将被推到这一点, a
(如果它具有不超过其它键2
)为:
a #=> {2=>[3,4,5,2]]}