count = Hash.new(0)
puts "count=#{count}"
# count={}
%w[a b b c c c].each do |char|
count[char] += 1
end
puts "count=#{count}"
# count={"a"=>1, "b"=>2, "c"=>3}
count = Hash.new
puts "count=#{count}"
%w[a b b c c c].each do |char|
count[char] += 1
# Fails: in `block in <main>': undefined method `+' for nil:NilClass (NoMethodError)
end
puts "count=#{count}"
4条答案
按热度按时间3gtaxfhh1#
如果您尝试访问哈希中不存在的键,0将是回退
举例来说:
count = Hash.new
->count['key'] => nil
vs
count = Hash.new(0)
->count['key'] => 0
t8e9dugd2#
下面是@jeremy-ramos的回答和@mu-is-too-short的评论。
有两个常见的陷阱与默认哈希值以这种方式。
1.意外共享引用。
Ruby在内存中使用完全相同的对象,作为每个丢失键的默认值。
对于不可变对象(如
0
),没有问题。但是,你可能想写这样的代码:或
这不是你所期望的。而不是
hash[unknown_key]
返回一个新的,空的数组或散列,它将为每个键返回完全相同的数组/散列对象。这样做:
产生一个hash,其中
key1
和key2
都指向包含[value1, value2]
的同一个数组对象。参见related question here
解决方案
为了解决这个问题,你可以用一个默认的块参数来创建一个散列(每当访问一个丢失的键时就会调用这个参数,让你给这个丢失的键赋值)。
2.缺键赋默认值
当您访问一个返回默认值的缺失键时,您可能会期望散列现在将包含该键和返回的值。它没有。Ruby不会修改哈希值,它只是返回默认值。例如:
解决方案
这种混淆也可以使用块方法来解决,其中可以显式设置键值。
qvsjd97n3#
Hash.new
文档对此不是很清楚。我希望下面的例子能澄清Hash.new(0)
的区别和常见用法之一。第一段代码使用
Hash.new(0)
。哈希的默认值为0,当遇到新键时,它们的值为0。此方法可用于计算数组中的字符数。第二段代码失败,因为键的默认值(未赋值时)是
nil
。此值不能用于附加(计数时),并生成错误。另见:
What's the difference between "Hash.new(0)" and "{}"
jhiyze9q4#
TL;DR当你使用
Hash.new
初始化hash时,你可以设置默认值或默认proc(如果给定的键不存在,将返回的值)关于理解这个魔术的问题,首先你需要知道Ruby哈希有默认值。要访问默认值,可以使用
Hash#default
方法默认值为
nil
您可以使用
Hash#default=
设置默认值非常重要的一点:使用可变对象作为默认值是危险,因为会有如下副作用:
要避免这种情况,可以使用
Hash#default_proc
和Hash#default_proc=
方法设置
default
将取消default_proc
,反之亦然返回
Hash.new
当你传递参数给这个方法时,你初始化了默认值。
当你把block传递给这个方法时,你初始化了默认的proc。