如何在调用super时将block置为nil,避免块代码重复执行?
解决Ruby中继承方法导致块重复执行的问题
看起来你遇到的问题是子类B的foo方法先执行了一次块,调用super时又把原块传给父类A的foo,导致块代码被执行了两次。而且你没法修改A的代码,还得保留A的foo在有块传入时的特殊行为——这确实有点棘手,不过有个很稳妥的解决方案。
最优方案:传递“复用结果”的块给super
核心思路是:在B里先执行一次原块拿到结果,然后调用super时,传递一个不会重复执行原块逻辑、只返回已有结果的新块。这样A的foo里的block_given?仍然会返回true(满足你需要的有块行为),但yield只会拿到之前的结果,不会再次触发原块的代码。
修改后的代码如下:
class A def foo if block_given? result = yield # do stuff with the yield result puts "A is processing yield result: #{result}" end # some more code puts "A's additional code runs" end end class B < A def foo # 先执行原块,拿到结果 block_result = yield # process block results and store it puts "B stored block result: #{block_result}" # 调用super时传递新块,直接返回已有结果 super { block_result } end end B.new.foo { puts "block called"; "sample result" } # 输出: # block called # B stored block result: sample result # A is processing yield result: sample result # A's additional code runs
可以看到,原块只执行了一次,同时A的foo完全保留了有块传入时的处理逻辑。
其他可选方案(不推荐,仅作参考)
如果你确实想让A的foo里的block_given?返回false,可以在调用super时显式不传递块(用super()而非super):
class B < A def foo block_result = yield puts "B stored block result: #{block_result}" # 显式不传递块,A的foo中block_given?返回false super() end end
但这个方法的问题是,A的foo会执行无块时的逻辑,不符合你“保留有块行为”的要求,所以仅当你不需要A的有块处理逻辑时才考虑使用。
内容的提问来源于stack exchange,提问作者23tux
相关产品推荐
相关产品推荐

