【问题标题】:Ruby splat operator changing value inside loopRuby splat 运算符在循环内更改值
【发布时间】:2014-12-13 01:19:00
【问题描述】:

我想定义一个可以采用可选数量的参数和散列的方法,就像这样

def foo(*b, **c)
  2.times.map.with_index { |i|
    new_hash, new_array = {}, b
    c.map { |key, value| new_hash[key] = value[i] unless value[i].nil? }
    new_array << new_hash if new_hash.length > 0
    send(:bar, new_array)
  }
end

def bar(*b)
  p b
end

如果我正确理解了 splat 和 double splat 运算符(我对此表示怀疑),那么这应该将数组 b 发送到 bar 方法,并且只添加来自 foonew_hash 如果它包含一些东西。但是,发生了一些奇怪的事情 - 我将尝试用下面的一些 sn-ps 来说明

# invoking #foo 
foo(a, key: 'value')

# first iteration of loop in #foo
  # i is 0
  # b is []
  # c is { :key => ['value1'] }
  # send(:bar, new_array) => send(:bar, [{:key => 'value1'}])
  # bar yields: [{:key => 'value1'}]

然而,现在发生了一些事情

# second iteration of loop in #foo
  # i is 1
  # b is [:key => 'value1'] <---- why?
  # c is { :key => ['value1']

为什么b 的值在foo 的循环内发生了变化?

编辑更新了代码以反映每次迭代都会创建一个新数组

【问题讨论】:

  • 您的代码与您的示例完全不匹配。
  • 啊!您刚刚对其进行了编辑以删除您所询问的错误!
  • 老兄,我想澄清一下我的观点,因为我问这个问题时显然很累。

标签: ruby splat


【解决方案1】:
new_hash, new_array = {}, b

这不会创建b 的副本。现在new_arrayb 指向同一个对象。就地修改一个会修改另一个。

new_array << new_hash

这会在原地修改new_array(因此修改b),因此新元素将保留在下一次迭代中。使用 + 之类的东西,它会创建一个副本:

send(:bar, *(b + (new_hash.empty? ? [] : [new_hash])))

【讨论】:

  • 是的,很抱歉我提交的第一个代码,我想我写的时候很累:p。无论如何,send 语句在代码库中没有使用硬编码符号,我使用:bar 符号只是为了说明目的。带索引的 map 也一样(顺便说一句,在代码体中使用)。
  • 明白了。下次您在 Stack Overflow 上提问时,请考虑创建 SSCCE。 1) 省略不必要的细节会让人们更容易理解您的问题,2) 它可能会帮助在您提出问题之前找出问题!
  • 啊,这是个好建议。我想我也刚刚意识到我的错误,因为我正在操作的参数在一个已生成的块内。
猜你喜欢
  • 2013-07-04
  • 2010-10-21
  • 2020-03-13
  • 2014-04-17
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
相关资源
最近更新 更多