Ruby哈希默认值行为 [英] Ruby hash default value behavior
问题描述
def test_default_value_is_the_same_object $ b我正在阅读Ruby Koans,并且我打了#41,我相信是这样的: $ b hash = Hash.new([])
hash [:one]<< uno
hash [:two]<< dos
assert_equal [uno,dos],hash [:one]
assert_equal [uno,dos],hash [:two]
assert_equal [uno,dos],hash [:three]
assert_equal true,hash [:one] .object_id == hash [:two] .object_id
end
它无法理解行为,所以我谷歌搜索并找到奇怪的ruby行为时使用哈希默认值,例如Hash.new([]),它很好地回答了问题。
所以我理解这是如何工作的,我的问题是,为什么默认值如递增的整数在使用过程中不会改变?例如: putsText please:
text = gets.chomp
words = text.split()
频率= Hash.new(0)
words.each {| word |频率[word] + = 1}
这会带用户输入并计算每个单词的次数因为总是使用默认值0,所以它工作正常。
我有一种感觉,它与<<
运算符,但我很乐意解释。
其他答案似乎表明差异行为是由于整数
s是不可变的, Array
s是可变的。但这是误导。区别不在于Ruby的创建者决定使一个不可变,另一个可变。不同之处在于你,程序员决定改变其中一个而不改变另一个。 问题不是是否 Array
s是可变的,问题是你是否改变它。
你可以通过使用 Array
s来获得上面看到的行为。观察:
一个默认数组带有变异
带有变异
hsh = Hash.new([])
hsh [:1]<< 'one'
hsh [:two]<< 'two'
hsh [:不存在]
#=> ['one','two']
#因为我们突变了默认值,所以不存在的键会返回更改后的值
hsh
#=> {}
#但是我们从来没有改变哈希本身,因此它仍然是空的!
一个默认 Array
无突变
hsh = Hash.new([])
hsh [:one] + = ['one']]
hsh [:two] + = ['two']
#这是hsh [:two] = hsh [:two] + ['two']
$ b $的语法糖b hsh [:nonexistant]
#=> []
#我们没有改变默认值,它仍然是一个空数组
hsh
#=> {:one => ['one'],:two => ['two']}
#这次,我们*做了*变异哈希。
每次都有新的不同的 Array
突变
hsh = Hash.new {[]}
#这次,而不是默认的*值*我们使用默认*块*
hsh [:1]<< 'one'
hsh [:two]<< 'two'
hsh [:不存在]
#=> []
#我们*改变了默认值,但每次都是新鲜的。
hsh
#=> {}
#但是我们从来没有改变哈希本身,因此它仍然是空的!
hsh = Hash.new {| hsh,key | hsh [key] = []}
#这次,我们使用了一个默认的* block *
#而不是默认的*值,而block不仅返回*默认值,它也是*指定* it
hsh [:one]<< 'one'
hsh [:two]<< 'two'
hsh [:不存在]
#=> []
#我们*改变了默认值,但每次都是新鲜的。
hsh
#=> {:one => ['one'],:two => ['two'],:不存在=> []}
I'm going through Ruby Koans, and I hit #41 which I believe is this:
def test_default_value_is_the_same_object
hash = Hash.new([])
hash[:one] << "uno"
hash[:two] << "dos"
assert_equal ["uno","dos"], hash[:one]
assert_equal ["uno","dos"], hash[:two]
assert_equal ["uno","dos"], hash[:three]
assert_equal true, hash[:one].object_id == hash[:two].object_id
end
It could not understand the behavior so I Googled it and found Strange ruby behavior when using Hash default value, e.g. Hash.new([]) that answered the question nicely.
So I understand how that works, my question is, why does a default value such as an integer that gets incremented not get changed during use? For example:
puts "Text please: "
text = gets.chomp
words = text.split(" ")
frequencies = Hash.new(0)
words.each { |word| frequencies[word] += 1 }
This will take user input and count the number of times each word is used, it works because the default value of 0 is always used.
I have a feeling it has to do with the <<
operator but I'd love an explanation.
The other answers seem to indicate that the difference in behavior is due to Integer
s being immutable and Array
s being mutable. But that is misleading. The difference is not that the creator of Ruby decided to make one immutable and the other mutable. The difference is that you, the programmer decided to mutate one but not the other.
The question is not whether Array
s are mutable, the question is whether you mutate it.
You can get both the behaviors you see above, just by using Array
s. Observe:
One default Array
with mutation
hsh = Hash.new([])
hsh[:one] << 'one'
hsh[:two] << 'two'
hsh[:nonexistent]
# => ['one', 'two']
# Because we mutated the default value, nonexistent keys return the changed value
hsh
# => {}
# But we never mutated the hash itself, therefore it is still empty!
One default Array
without mutation
hsh = Hash.new([])
hsh[:one] += ['one']
hsh[:two] += ['two']
# This is syntactic sugar for hsh[:two] = hsh[:two] + ['two']
hsh[:nonexistant]
# => []
# We didn't mutate the default value, it is still an empty array
hsh
# => { :one => ['one'], :two => ['two'] }
# This time, we *did* mutate the hash.
A new, different Array
every time with mutation
hsh = Hash.new { [] }
# This time, instead of a default *value*, we use a default *block*
hsh[:one] << 'one'
hsh[:two] << 'two'
hsh[:nonexistent]
# => []
# We *did* mutate the default value, but it was a fresh one every time.
hsh
# => {}
# But we never mutated the hash itself, therefore it is still empty!
hsh = Hash.new {|hsh, key| hsh[key] = [] }
# This time, instead of a default *value*, we use a default *block*
# And the block not only *returns* the default value, it also *assigns* it
hsh[:one] << 'one'
hsh[:two] << 'two'
hsh[:nonexistent]
# => []
# We *did* mutate the default value, but it was a fresh one every time.
hsh
# => { :one => ['one'], :two => ['two'], :nonexistent => [] }
这篇关于Ruby哈希默认值行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!