1

オプションの量の引数とハッシュを取ることができるメソッドを定義したいです。

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をメソッドに送信し、何かが含まれている場合にのみfrombarを追加する必要があります。しかし、何か奇妙なことが起こります - 以下のいくつかのスニペットで説明してみますnew_hashfoo

# 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ですか?

edit反復ごとに新しい配列が作成されることを反映するようにコードを更新しました

4

1 に答える 1

2
new_hash, new_array = {}, b

これは のコピーを作成しませんb次に、同じオブジェクトnew_arraybポイントします。一方をインプレースで変更すると、もう一方も変更されます。

new_array << new_hash

それはその場で変更されnew_array(したがってb)、新しい要素は次の反復に残ります。のようなものを使用して+、コピーを作成します。

send(:bar, *(b + (new_hash.empty? ? [] : [new_hash])))
于 2014-10-17T12:52:23.370 に答える