我想定义一个方法,它可以采用可选数量的参数和哈希值,如此
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
方法,并且只添加new_hash
来自foo
,如果它包含某些内容。然而,发生了一些奇怪的事情 - 我将尝试用下面的一些片段进行说明
# 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
的值发生了变化?
编辑更新代码以反映为每次迭代创建的新数组
答案 0 :(得分:2)
new_hash, new_array = {}, b
这不会创建b
的副本。现在new_array
和b
指向同一个对象。在原地修改一个将修改另一个。
new_array << new_hash
它会修改new_array
(以及b
),因此新元素将保留在下一次迭代中。使用类似+
的内容创建副本:
send(:bar, *(b + (new_hash.empty? ? [] : [new_hash])))