Object#tap
常常被滥用,我们经常遇到下面的代码:
obj = SomeClass.new.tap do |o|
o.blah = true
end
这种写法有个毛线用处?根本没有节省一行代码,并且这代码块也增加了理解难度。还如不下面这种传统的写法:
obj = SomeClass.new
obj.blah = true
obj
代码行数一样;返回同样的结果;只有一个局部变量;逻辑清晰易懂。
那么什么情况下应该使用 tap
呢,我觉得下面这样的例子比较合适:
list
.map { |o| o.foo.bar }
.reverse
.more_transform .tap { |things| puts "transformed: #{things.inspect}" }
.even_more_transformations
tap
将代码块引入到了方法链。这招在进行调试的时候特别有效。比如:
User
.active .tap { |users| puts "Users so far: #{users.size}" }
.non_admin .tap { |users| puts "Users so far: #{users.size}" }
.at_least_years_old(25) .tap { |users| puts "Users so far: #{users.size}" }
.residing_in('USA')
不需要改动原来的方法链,也不需要引入储存数据的临时变量就可以在方法链上的任意一点进行调试。
所以结论是:tap
是一种不会中断正常执行的代码进行的快速调试方法。
def rockwell_retro_encabulate
provide_inverse_reactive_current
synchronize_cardinal_graham_meters
@result.tap(&method(:puts))
# Will debug `@result` just before returning it.
end
改变对象
tap
方法会返回原对象,如果你想返回一个被改变的对象咋办?
Combinatory method like tap, but able to return a different value? The magic is break
in tap
returns another value.
def best_nice_method
something_complex(a, b, c).tap |obj|
break obj.one_more_method_call if a_predicate_check?
end
end
原文