【发布时间】:2019-08-05 18:40:03
【问题描述】:
TL;DR
我通过反复试验解决了这个问题,但我对 splat 运算符和pp 方法如何始终如一地给我一个与我认为的不同的对象的理解显然存在差距。我想了解这个差距,并确定一种更好的方法来合并散列数组。我还希望将来能够更有效地调试这类事情。
首先是代码示例和调试步骤。我的半满意解决方案和更详细的问题在底部。
代码
我正在使用 MRI Ruby 2.6.2。给定类 Foo,我希望 Foo#windows 返回一个合并的哈希。这是该类的一个最小示例:
class Foo
attr_reader :windows
def initialize
@windows = {}
end
def pry
{ pry: "stuff pry\r" }
end
def irb
{ irb: "stuff irb\r" }
end
def windows= *hashes
@windows.merge! *hashes
end
end
foo = Foo.new
foo.windows = foo.pry, foo.irb
问题(调试)
但是,尝试分配给 foo.windows(或者甚至尝试使用 foo.windows= foo.pry, foo.irb 帮助解析器不那么模棱两可)我从 REPL 中得到一个异常:
TypeError: 没有将 Array 隐式转换为 Hash
但是,如果我使用单例方法修改实例以捕获 *hashes 参数的值,我会看到一个可以很好地合并的哈希数组。考虑以下几点:
def foo.windows= *hashes
pp *hashes
end
foo.windows = foo.pry, foo.irb
#=> [{:pry=>"stuff pry\r"}, {:irb=>"stuff irb\r"}]
{}.merge *[{:pry=>"stuff pry\r"}, {:irb=>"stuff irb\r"}]
#=> {:pry=>"stuff pry\r", :irb=>"stuff irb\r"}
从#pp 获取输出给了我一些按预期工作的东西。然而,当我更深入地挖掘时,事实证明,在 Hash 的额外嵌套上有些东西:
def foo.windows= *hashes
pp *hashes.inspect
end
foo.windows = foo.pry, foo.irb
"[[{:pry=>\"stuff pry\\r\"}, {:irb=>\"stuff irb\\r\"}]]"
即使返回值没有显示出来,还有一组额外的方括号导致数组嵌套。我真的不明白他们来自哪里。
什么有效
因此,无论出于何种原因,我都必须分解数组,将其展平,然后才能合并:
def foo.windows= *hashes
@windows.merge! *hashes.flatten
end
# The method still returns unexpected results here, but...
foo.windows = foo.pry, foo.irb
#=> [{:pry=>"stuff pry\r"}, {:irb=>"stuff irb\r"}]
# the value stored in the instance variable is finally correct!
foo.windows
#=> {:pry=>"stuff pry\r", :irb=>"stuff irb\r"}
但是为什么?
所以是的,我已经设法解决了这个问题。但是,我的问题实际上是关于 为什么 合并哈希不能按预期工作,以及额外的嵌套层来自哪里。我不期待一个哈希数组,而是一个哈希数组。我的理解是否存在差距,或者这是某种奇怪的边缘情况?
更重要的是,为什么调试如此困难?我希望 #pp 或 #inspect 向我展示我真正拥有的对象,而不是在我清楚地拥有一个包含哈希的数组数组时向我展示一个哈希数组作为返回值。
【问题讨论】:
-
你使用的是哪个版本的 Ruby?
-
@SRack MRI 2.6.2.
-
=需要单个值;我怀疑 Ruby 正在将您的参数h1, h2转换为单个值。*splat 将(假定的)可变参数移动到一个数组中——由于它接收单个值,您会看到嵌套。例如,stackoverflow.com/q/9280623/438992 -
pp没有按照你的想法做,因为你在去喷溅。
标签: arrays ruby hash merge splat