4

splat 演算子を使用してブロックに引数を参照渡しすると、引数がコピーされるようです。

私はこれを持っています:

def method
  a = [1,2,3]
  yield(*a)
  p a
end

method {|x,y,z| z = 0}
#=> this puts and returns [1, 2, 3] (didn't modified the third argument)

これらの引数を参照渡しするにはどうすればよいですか? 配列を直接渡すとうまくいくようですが、splat 演算子の方がはるかに実用的で、直感的で、保守が容易です。

4

4 に答える 4

7
  1. Ruby では、以前に存在するかどうかに関係なくx = value、新しいローカル変数を作成することになります (存在する場合、名前は単純に再バインドされ、元の値は変更されません)。xしたがって、この方法で変数をその場で変更することはできません。

  2. 整数は不変です。したがって、整数を送信した場合、その値を変更する方法はありません。変更可能なオブジェクト (文字列、ハッシュ、配列など) を変更できることに注意してください。

    def method
      a = [1, 2, "hello"]
      yield(*a)
      p a
    end
    
    method { |x,y,z| z[1] = 'u' }
    # [1, 2, "hullo"]
    

注: 私はあなたの質問に答えようとしましたが、私の意見では、メソッドまたはブロック内の引数を更新すると、バグのあるコードが発生します (参照透過性はもうありません)。新しい値を返し、必要に応じて呼び出し元が変数自体を更新できるようにします。

于 2012-07-31T18:00:49.707 に答える
2

ここで問題になるのは=記号です。これにより、ローカル変数zが別のオブジェクトに割り当てられます。

この例を文字列で見てみましょう:

def method
  a = ['a', 'b', 'c']
  yield(*a)
  p a
end

method { |x,y,z| z.upcase! }   # => ["a", "b", "C"]

zこれは、配列の 3 番目のオブジェクトと同じであることを明確に示しています。

ここでのもう1つのポイントは、あなたの例が数値であることです。Fixnum には固定 ID があります。そのため、同じオブジェクト ID を維持しながら番号を変更することはできません。=Fixnum を変更するには、変数に新しい番号を代入する必要がありますinc!(このようなメソッドは Fixnum には存在しません)。

于 2012-07-31T18:01:29.783 に答える
0

はい...配列にはオブジェクトへのリンクが含まれています。次に使用するコードでは、ブロック内で、配列内にあっyield(*a)たオブジェクトを指す変数を操作します。次に、コードサンプルを探します。

daz@daz-pc:~/projects/experiments$ irb
irb(main):001:0> a = 1
=> 1
irb(main):002:0> a.object_id
=> 3
irb(main):003:0> a = 2
=> 2
irb(main):004:0> a.object_id
=> 5

したがって、ブロックでは、古いオブジェクトを変更せずに、別のオブジェクトを作成して変数に設定するだけです。ただし、配列には古いオブジェクトへのリンクが含まれています。

デバッグのものを見てください:

def m
  a = [1, 2]
  p a[0].object_id
  yield(*a)
  p a[0].object_id
end

m { |a, b| p a.object_id; a = 0; p a.object_id }

出力:

3
3
1
3
于 2012-07-31T17:02:24.897 に答える
0

これらの引数を参照渡しするにはどうすればよいですか?

Ruby では引数を参照渡しすることはできません。Ruby は値渡しです。いつも。例外も、ifs も buts もありません。

配列を直接渡すとうまくいくようです

私はそれを非常に疑っています。Ruby では、参照によって引数を渡すことはできません。限目。

于 2012-08-01T00:16:05.220 に答える