You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:27:42