正在学习使用Ruby编码。我正在学习哈希(hashes),但是不理解这段代码:count = Hash.new(0)
。它说0是一个默认值,但是当我在irb上运行它时,它给出了一个空的哈希{}。如果0是一个默认值,为什么我看不到类似于count ={0=>0}
的东西呢?还是零是累加器,但不参与键或值?谢谢
正在学习使用Ruby编码。我正在学习哈希(hashes),但是不理解这段代码:count = Hash.new(0)
。它说0是一个默认值,但是当我在irb上运行它时,它给出了一个空的哈希{}。如果0是一个默认值,为什么我看不到类似于count ={0=>0}
的东西呢?还是零是累加器,但不参与键或值?谢谢
如果您尝试访问哈希表中不存在的键,0将作为后备返回值。
例如:
count = Hash.new
-> count['key'] => nil
相比之下,
count = Hash.new(0)
-> count['key'] => 0
进一步阐述 @jeremy-ramos 的回答和 @mu-is-too-short 的评论。
使用默认哈希值有两个常见的“坑点”。
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] = [] }
当你访问一个返回默认值的不存在的键时,你可能期望哈希表现在包含具有返回值的该键。它不会这样做。Ruby不会修改哈希,它只是返回默认值。例如:
hash = Hash.new(0) #$> {}
hash.keys.empty? #$> true
hash[:foo] #$> 0
hash[:foo] == 0 #$> true
hash #$> {}
hash.keys.empty? #$> true
使用块级方法可以解决这种混淆,其中键值可以明确设置。
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}"
参见:
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
Hash.new([])
,会意外共享引用,因此h = Hash.new([]); h[:v].push(11)
会产生副作用;(2)Hash.new(some_value)
没有自动创建新键,所以h = Hash.new(0); puts h[:v]
会输出0
但不会将:v
添加为键,但如果你使用h = Hash.new { |h, k| h[k] = 0 }
开始,则会添加。不确定指的是哪一个。 - mu is too shortinject
参数的东西吗? - melcher