Ruby 方法数组#<<不更新哈希数组 [英] Ruby method Array#&lt;&lt; not updating the array in hash

查看:51
本文介绍了Ruby 方法数组#<<不更新哈希数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

灵感来自 我如何用数组编组散列? 我想知道 Array#<< 在以下代码中无法正常工作的原因是什么:

Inspired by How can I marshal a hash with arrays? I wonder what's the reason that Array#<< won't work properly in the following code:

h = Hash.new{Array.new}
#=> {}
h[0]
#=> []
h[0] << 'a'
#=> ["a"]
h[0]
#=> [] # why?!
h[0] += ['a']
#=> ["a"]
h[0]
#=> ["a"] # as expected

这是否与 << 就地更改数组而 Array#+ 创建一个新实例的事实有关?

Does it have to do with the fact that << changes the array in-place, while Array#+ creates a new instance?

推荐答案

如果您使用 Hash.new 的块形式创建一个 Hash,则该块会在每个当您尝试访问实际上不存在的元素时.所以,让我们看看会发生什么:

If you create a Hash using the block form of Hash.new, the block gets executed every time you try to access an element which doesn't actually exist. So, let's just look at what happens:

h = Hash.new { [] }
h[0] << 'a'

这里首先计算的是表达式

The first thing that gets evaluated here, is the expression

h[0]

当它被评估时会发生什么?好吧,块开始运行:

What happens when it gets evaluated? Well, the block gets run:

[]

这不是很令人兴奋:该块只是创建一个空数组并返回它.它不做任何其他事情.特别是,它不会以任何方式改变 h:h 仍然是空的.

That's not very exciting: the block simply creates an empty array and returns it. It doesn't do anything else. In particular, it doesn't change h in any way: h is still empty.

接下来,带有一个参数 'a' 的消息 << 被发送到 h[0] 的结果,即块的结果,它只是一个空数组:

Next, the message << with one argument 'a' gets sent to the result of h[0] which is the result of the block, which is simply an empty array:

[] << 'a'

这是做什么的?它将元素 'a' 添加到一个空数组中,但由于该数组实际上并未分配给任何变量,因此它会立即被垃圾收集并消失.

What does this do? It adds the element 'a' to an empty array, but since the array doesn't actually get assigned to any variable, it is immediately garbage collected and goes away.

现在,如果你再次评估 h[0]:

Now, if you evaluate h[0] again:

h[0] # => []

h 仍然 是空的,因为没有分配给它,因此键 0 仍然不存在,这意味着块被再次运行,这意味着它再次返回一个空数组(但请注意,它现在是一个全新的、不同的空数组).

h is still empty, since nothing ever got assigned to it, therefore the key 0 is still non-existent, which means the block gets run again, which means it again returns an empty array (but note that it is a completely new, different empty array now).

h[0] += ['a']

这里发生了什么?首先,操作符assign被脱糖为

What happens here? First, the operator assign gets desugared to

h[0] = h[0] + ['a']

现在,对 右侧h[0] 进行评估.它返回什么?我们已经讨论过这个: h[0] 不存在,因此块运行,块返回一个空数组.同样,这是一个全新的 第三 空数组.这个空数组被发送带有参数 ['a'] 的消息 +,这导致它返回另一个新数组,它是数组['a'].然后这个数组被分配给 h[0].

Now, the h[0] on the right side gets evaluated. And what does it return? We already went over this: h[0] doesn't exist, therefore the block gets run, the block returns an empty array. Again, this is a completely new, third empty array now. This empty array gets sent the message + with the argument ['a'], which causes it to return yet another new array which is the array ['a']. This array then gets assigned to h[0].

最后,此时:

h[0] # => ['a']

现在你终于真的把一些东西放进了 h[0] 所以,很明显,你得到了你放入的东西.

Now you have finally actually put something into h[0] so, obviously, you get out what you put in.

那么,要回答您可能遇到的问题,为什么不拿出您输入的内容呢?你一开始就没有放任何东西!

So, to answer the question you probably had, why don't you get out what you put in? You didn't put anything in in the first place!

如果你真的想分配到块内的散列,你必须,很好地分配到块内的散列:

If you actually want to assign to the hash inside the block, you have to, well assign to the hash inside the block:

h = Hash.new {|this_hash, nonexistent_key| this_hash[nonexistent_key] = [] }
h[0] << 'a'
h[0] # => ['a']

如果您查看所涉及对象的身份,实际上很容易了解您的代码示例中发生了什么.然后你可以看到,每次调用h[0],你都会得到一个不同的数组.

It's actually fairly easy to see what is going on in your code example, if you look at the identities of the objects involved. Then you can see that everytime you call h[0], you get a different array.

这篇关于Ruby 方法数组#<<不更新哈希数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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