使用具有默认值的哈希

问题描述 投票:0回答:4

正在学习使用 ruby 编写代码。我正在学习哈希,但我不明白这段代码:

count = Hash.new(0)
。它说 0 是默认值,但是当我在 irb 上运行它时,它给了我一个空的哈希值 {}。如果 0 是默认值,为什么我看不到类似
count ={0=>0}
的内容。或者零是累加器但不转到键或值?谢谢

ruby default new-operator ruby-hash
4个回答
7
投票
如果您尝试访问哈希中不存在的密钥,

0 将是后备

例如:

count = Hash.new
->
count['key'] => nil

count = Hash.new(0)
->
count['key'] => 0


6
投票

扩展@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

产生一个散列,其中

key1
key2
都指向包含
[value1, value2]

的同一个数组对象

请参阅此处相关问题

解决方案

要解决此问题,您可以创建一个带有默认块参数的哈希(每当访问丢失的键时就会调用该哈希,并让您为丢失的键分配一个值)

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

解决方案

使用块方法也可以解决这种混乱,可以显式设置它们的键值。


3
投票

Hash.new
文档对此不是很清楚。我希望下面的示例能够阐明
Hash.new(0)
的区别和常用用法之一。

第一块代码使用

Hash.new(0)
。 hash的默认值为0,当遇到新的key时,其值为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}"

另请参阅:

“Hash.new(0)”和“{}”有什么区别


2
投票

TL;DR 当您使用

Hash.new
初始化哈希时,您可以设置默认值或默认过程(如果给定键不存在则返回的值)

关于理解这个魔法的问题,首先你需要知道 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_proc
Hash#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

当您将块传递给此方法时,您会初始化默认过程

hash = Hash.new { 0 }

hash.default # => nil
hash[:key] # => 0
© www.soinside.com 2019 - 2024. All rights reserved.