关于Object#tap的误解

时间:2013-03-26 07:00:47

标签: ruby

这是我的简单测试代码:

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

2 个答案:

答案 0 :(得分:8)

原因是+ =运算符不会更改原始对象。那么在块中创建对它的引用会发生什么呢,将引用更改为指向另一个对象,该对象大于10然后返回。 0的值保持不变。

关于它的事情 - 这就是你想要发生的事情。 + =运算符不会更改其操作的对象。它返回另一个不同的对象并为其分配引用。这就像:

  v = 0
  v = v + 10

在此之后你不希望0 == 10成立,对吗?

答案 1 :(得分: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属性,即使只是包含一个元素的数组:

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

p test_function[0]
=> 10

。 。 。取决于你想要做什么?