加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

为什么Hash#使用splat运算符合并返回Hashes数组而不是Hashes数组

发布时间:2020-12-17 02:57:27 所属栏目:百科 来源:网络整理
导读:TL; DR 我通过反复试验解决了这个问题,但是我对splat运算符和pp方法如何一直给我一个不同于我认为的对象的理解显然存在差距.我想了解这个差距,并找出合并散列数组的更好方法.我也希望能够在未来更有效地调试这类事情. 首先是代码示例和调试步骤.我的半满意解
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 pryr" }
  end 

  def irb
    { irb: "stuff irbr" }
  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 pryr"},{:irb=>"stuff irbr"}]

{}.merge *[{:pry=>"stuff pryr"},{:irb=>"stuff irbr"}]
#=> {:pry=>"stuff pryr",:irb=>"stuff irbr"}

从#pp获取输出给了我一些按预期工作的东西.然而,当我深入挖掘时,事实证明有些东西正在层叠在Hash的额外嵌套上:

def foo.windows= *hashes
  pp *hashes.inspect
end
foo.windows = foo.pry,foo.irb

06003

即使返回值没有显示,也有一组额外的方括号导致数组嵌套.我真的不明白他们来自哪里.

什么有用

因此,无论出于何种原因,我必须将数据展开,展平它,然后我就能合并:

def foo.windows= *hashes
  @windows.merge! *hashes.flatten
end

# The method still returns unexpected results here,but...
foo.windows = foo.pry,{:irb=>"stuff irbr"}]

# the value stored in the instance variable is finally correct!
foo.windows
#=> {:pry=>"stuff pryr",:irb=>"stuff irbr"}

但为什么?

所以是的,我已经设法解决了这个问题.但是,我的问题是关于为什么合并散列不能按预期工作,以及额外的嵌套层来自何处.我不期望哈希数组数组,而是哈希数组.我的理解是否存在差距,或者这是某种奇怪的边缘情况?

更重要的是,为什么这么难以调试?我希望#pp或#inspect向我展示我真正拥有的对象,而不是在我清楚地拥有包含Hash的数组数组时向我显示一个Hashes数组作为返回值.

解决方法

你错过的是 Ruby parser doesn’t allow setter methods with more than one parameter.

当您将多个参数传递给setter时,它们会自动放在一个数组上(因为a = 1,2表示与a = [1,2]相同):

def foo.a=(values)
  pp values
end

foo.a = 1,2 # [1,2]

但是,如果定义了splat参数,因为该数组被认为是单个参数,所以会发生这种情况:

def foo.a=(*values)
  pp values
end

foo.a = 1,2 # [[1,2]]

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读