4

これが私の簡単なテストコードです:

def test_function
  0.tap do |v|
    v += 10
  end
end

p test_function

なぜここで0になるのですか?私は10を得るのを待っていました。

アップデート:

class TestClass
    def initialize
        @v = 0
    end

    def inc 
        @v = @v + 1
    end
end

def test_function
    0.tap do |v|
        v += 10
    end
end

def test_function_2
    TestClass.new.tap { |obj|
        obj.inc
    }
end

p test_function
p test_function_2

0

TestClass:0x29244f0 @ v = 1

4

2 に答える 2

8

その理由は、元のオブジェクトが+=演算子によって変更されないためです。したがって、ブロック内にその参照を作成し、参照を変更して、10だけ大きい他のオブジェクトを指すようにしてから、戻るとどうなりますか。0の値は同じままです。

そしてそれについてのこと-これはあなたが起こりたいことです。+ =演算子は、操作するオブジェクトを変更しません。別の異なるオブジェクトを返し、それに参照を割り当てます。これは次のようなものです:

  v = 0
  v = v + 10

0 == 10この後、あなたは真実であるとは思わないでしょう?

于 2013-03-26T07:10:19.673 に答える
4

ここに追加の答えがあります:メソッドtapは元のオブジェクトを返します。たとえば、レポート、統計の収集、ログ記録などの副作用に使用できます。元のオブジェクトへの追加の内部アクセスは提供されません。

v = [0,1,2]
v.tap { |array| array.map { |x| x + 1 } }
=> [0,1,2]

v.tap { |array| array.map! { |x| x + 1 } }
=> [1,2,3]

test_function_2のバリアントを使用できます。この場合、制御するオブジェクトにはIntegerプロパティがあり、要素が1つだけの配列であっても次のようになります。

def test_function
  [0].tap do |v|
    v[0] += 10
  end
end

p test_function[0]
=> 10

。。。あなたがやろうとしていることに依存しますか?

于 2013-03-26T09:36:35.503 に答える