长话短说
我通过反复试验解决了这个问题,但我对 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: no implicit conversion of Array into 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 获取输出可以让我得到一些按预期工作的东西。然而,当我更深入地挖掘时,我发现有些东西在哈希的额外嵌套上分层:
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 向我展示我真正拥有的对象,而不是在我显然有一个包含哈希的数组数组时向我展示一个哈希数组作为返回值。
最佳答案
首先,*hashes
可能意味着两个截然不同的事情:
def windows=(*hashes)
表示“将传递给此方法的所有参数按出现顺序存储到数组hashes
中。”- 而
@windows.merge! *hashes
使用hashes
的项目作为方法调用merge!
的单独参数。
然而,当你有一个赋值方法时,listing several values automatically creates an array:
You can implicitly create an array by listing multiple values when assigning:
a = 1, 2, 3 p a # prints [1, 2, 3]
因此 foo.windows(foo.pry, foo.irb)
与
def windows(*hashes)
pp hashes
@windows.merge! *hashes
end
将按预期打印 [{:pry=>"stuff pry\r"}, {:irb=>"stuff irb\r"}]
。
但是因为你有一个赋值方法,你应该从你的定义中删除星号。
def windows=(hashes)
@windows.merge!(*hashes)
end
关于arrays - 为什么 Hash#merge 使用 splat 运算符返回哈希数组数组而不是哈希数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55169803/