这个红宝石片段如何工作?

时间:2014-05-05 14:00:31

标签: ruby hash

难题:

something = {}
another = something
('a'...'f').each do |x|
  puts "another = #{another} and x= #{x} and something = #{something}"
  another = (another[x] ||= {})
end
puts something

输出:

=>another = {} and x= a and something = {}
=>another = {} and x= b and something = {"a"=>{}}
=>another = {} and x= c and something = {"a"=>{"b"=>{}}}
=>another = {} and x= d and something = {"a"=>{"b"=>{"c"=>{}}}}
=>another = {} and x= e and something = {"a"=>{"b"=>{"c"=>{"d"=>{}}}}}

现在乍一看似乎是另一个'和'东西'两者都指向相同的哈希对象,但如果是这种情况,那么在输出中另一个哈希对象#39;会匹配某些东西'。那么变量'是什么'不是空哈希?

2 个答案:

答案 0 :(得分:6)

在Ruby中,一切都是一个对象,所有对象都使用指针传递(有例外,但它们不适用于此处)。当你这样做

something = {}
another = something

创建单个Hash对象,并且两个变量都指向同一个对象。当你这样做

another[x] ||= {}

创建单个Hash对象,并将指向该对象的指针添加到 another指向的哈希。另一种写作方式是

old_hash = another
new_hash = {}
old_hash[x] = new_hash
another = new_hash

请记住:所有这些分配只是围绕指向对象的指针移动。现在应该清楚another指向新的(空)哈希。但是,由于old_hash 还包含指向新哈希的指针,因此another将会看到新哈希值(即old_hash)的任何期货更改。这就是为什么something随着每次迭代而增长的原因。

你的例子与这种简单的情况没什么不同:

x = {}
y = {}
z = {}
x["a"] = y
y["b"] = z
z["c"] = {}
puts x
# {"a"=>{"b"=>{"c"=>{}}}}

您的示例只是反转最后三个分配 - 这对结果没有影响。

答案 1 :(得分:2)

  

现在乍一看它看起来像'另一个'和'某事'都指向同一个哈希对象,但如果是这样的情况那么   输出'另一个'将匹配'某事'。

因为somethinganother不再指向相同的对象。您已使用another重新分配another = (another[x] ||= {})。您可以致电something.object_idanother.object_id进行验证。

  

为什么another总是{}

因为你做的时候

another = (another[x] ||= {})

another是通过评估表达式(another[x] ||= {})返回的值{},这就是another成为{}的原因

并且,为了使您的代码正常工作,即您希望的方式只是删除another的重新分配,以便anothersomething指向同一个对象。

something = {}
another = something
('a'...'f').each do |x|
  puts "another = #{another} and x= #{x} and something = #{something}"
  another[x] ||= {}  ## Change to this
end
puts something

<强>输出:

another = {} and x= a and something = {}
another = {"a"=>{}} and x= b and something = {"a"=>{}}
another = {"a"=>{}, "b"=>{}} and x= c and something = {"a"=>{}, "b"=>{}}
another = {"a"=>{}, "b"=>{}, "c"=>{}} and x= d and something = {"a"=>{}, "b"=>{}, "c"=>{}}
another = {"a"=>{}, "b"=>{}, "c"=>{}, "d"=>{}} and x= e and something = {"a"=>{}, "b"=>{}, "c"=>{}, "d"=>{}}
 => "a"..."f" 
2.1.0 :265 >     puts something
{"a"=>{}, "b"=>{}, "c"=>{}, "d"=>{}, "e"=>{}}