ruby 使用具有默认值的哈希

pes8fvy9  于 12个月前  发布在  Ruby
关注(0)|答案(4)|浏览(80)

我正在学习用Ruby写代码。我正在学习哈希,我不明白这段代码:count = Hash.new(0)。它说0是默认值,但是当我在irb上运行它时,它给我一个空的hash {}。如果0是默认值,为什么我看不到像count ={0=>0}这样的东西。或者零是一个累加器,但不去键或值?谢谢

3gtaxfhh

3gtaxfhh1#

如果您尝试访问哈希中不存在的键,0将是回退
举例来说:
count = Hash.new -> count['key'] => nil
vs
count = Hash.new(0) -> count['key'] => 0

t8e9dugd

t8e9dugd2#

下面是@jeremy-ramos的回答和@mu-is-too-short的评论。
有两个常见的陷阱与默认哈希值以这种方式。

1.意外共享引用。

Ruby在内存中使用完全相同的对象,作为每个丢失键的默认值。
对于不可变对象(如0),没有问题。但是,你可能想写这样的代码:

hash = Hash.new([])
hash[key] << value

hash = Hash.new({})
hash[key][second_key] = value

这不是你所期望的。而不是hash[unknown_key]返回一个新的,空的数组或散列,它将为每个键返回完全相同的数组/散列对象。
这样做:

hash = Hash.new([])
hash[key1] << value1
hash[key2] << value2

产生一个hash,其中key1key2都指向包含[value1, value2]的同一个数组对象。
参见related question here

解决方案

为了解决这个问题,你可以用一个默认的块参数来创建一个散列(每当访问一个丢失的键时就会调用这个参数,让你给这个丢失的键赋值)。

hash = Hash.new{|h, key| h[key] = [] }

2.缺键赋默认值

当您访问一个返回默认值的缺失键时,您可能会期望散列现在将包含该键和返回的值。它没有。Ruby不会修改哈希值,它只是返回默认值。例如:

hash = Hash.new(0) #$> {} 
hash.keys.empty? #$> true
hash[:foo] #$> 0
hash[:foo] == 0 #$> true
hash #$> {}
hash.keys.empty? #$> true

解决方案

这种混淆也可以使用块方法来解决,其中可以显式设置键值。

qvsjd97n

qvsjd97n3#

Hash.new文档对此不是很清楚。我希望下面的例子能澄清Hash.new(0)的区别和常见用法之一。
第一段代码使用Hash.new(0)。哈希的默认值为0,当遇到新键时,它们的值为0。此方法可用于计算数组中的字符数。
第二段代码失败,因为键的默认值(未赋值时)是nil。此值不能用于附加(计数时),并生成错误。

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}"

另见:

What's the difference between "Hash.new(0)" and "{}"

jhiyze9q

jhiyze9q4#

TL;DR当你使用Hash.new初始化hash时,你可以设置默认值或默认proc(如果给定的键不存在,将返回的值)
关于理解这个魔术的问题,首先你需要知道Ruby哈希有默认值。要访问默认值,可以使用Hash#default方法
默认值为nil

hash = {}

hash.default # => nil

hash[:key] # => nil

您可以使用Hash#default=设置默认值

hash = {}

hash.default = :some_value

hash[:key] # => :some_value

非常重要的一点:使用可变对象作为默认值是危险,因为会有如下副作用:

hash = {}
hash.default = []

hash[:key] # => []

hash[:other_key] << :some_item # will mutate default value

hash[:key] # => [:some_value]
hash.default # => [:some_value]

hash # => {}

要避免这种情况,可以使用Hash#default_procHash#default_proc=方法

hash = {}

hash.default_proc # => nil

hash.default_proc = proc { [] }

hash[:key] # => []

hash[:other_key] << :some_item # will not mutate default value
hash[:other_key] # => [] # because there is no this key

hash[:other_key] = [:symbol]
hash[:other_key] << :some_item
hash[:other_key] # => [:symbol, :some_item]

hash[:key] # => [] # still empty array as default

设置default将取消default_proc,反之亦然

hash = {}

hash.default = :default

hash.default_proc = proc { :default_proc }

hash[:key] # => :default_proc

hash.default = :default

hash[:key] # => :default

hash.default_proc # => nil

返回Hash.new
当你传递参数给这个方法时,你初始化了默认值。

hash = Hash.new(0)

hash.default # => 0
hash.default_proc # => nil

当你把block传递给这个方法时,你初始化了默认的proc。

hash = Hash.new { 0 }

hash.default # => nil
hash[:key] # => 0

相关问题