Ruby哈希默认值行为 [英] Ruby hash default value behavior

查看:91
本文介绍了Ruby哈希默认值行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  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 Integers being immutable and Arrays 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 Arrays are mutable, the question is whether you mutate it.

You can get both the behaviors you see above, just by using Arrays. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆