【发布时间】:2022-11-22 05:00:11
【问题描述】:
我已将我的问题浓缩为我认为最小可重现的案例:
class AbortReading < RuntimeError; end
class SomeError < RuntimeError; end
def rno
retval = false
catch(:abort_reading) do
begin
yield
rescue AbortReading
puts "throw abort_reading"
throw :abort_reading
end # begin
puts "Setting to true"
retval = true
end # catch
ensure # rno
puts "rno returns #{retval.inspect}"
retval # return value
end
def rfb
success = rno do
begin
puts "failing"
fail SomeError
rescue SomeError
puts "intercepted SomeError"
fail AbortReading
end
end
puts "success=#{success.inspect}"
success
end
puts rfb
我有两种方法,rno 和rfb。 rno 应该会阻止。它返回 true,除非该块引发异常 AbortReading,在这种情况下它返回 false。注意 throw 有点不寻常的用法,它会过早地跳到 rno 的末尾;这个构造取自实际(更复杂)的代码,它确实有意义,我也在我的示例案例中使用它,因为我觉得问题的原因可能在这部分。
方法rfb使用rno,在它的主体中它首先引发一个SomeError并将这个异常变成一个AbortReading。这个有点奇怪的构造也取自原始实现。
我希望 rfb 的调用会导致 false,因为它会导致 AbortReading,然后 rno 会从中返回 false。但是,rfb 返回 nil。这意味着rfb里面的变量success已经被分配了,但是它永远不会收到retval的值。
运行代码产生输出
failing
intercepted SomeError
throw abort_reading
rno returns false
success=nil
请特别注意,rno 确实在它终止之前返回 false,但在 rfb 内部,值为 nil。这里发生了什么?
【问题讨论】:
标签: ruby