Ruby 的 $!仅在救援区块中有价值?

Does Ruby's $! hold value only in rescue block?

begin
  raise 'foo'
rescue
  puts $!.inspect # => #<RuntimeError: foo>
ensure
  puts $!.inspect # => nil
end
puts $!.inspect # => nil

用 Google 搜索但没有找到明确的答案。

只是想确认 $! 的生命周期(?),它是否仅在 rescue 块内具有价值?

$! 救援块中有错误,如果没有救援块,则确保块中有错误:

begin
  raise 'foo'
ensure
  puts $!.inspect # => #<RuntimeError: foo>
end

$! 在其他任何地方都具有值 nil

不,只读变量 $! 在任何地方都是可见和可用的,并且保存 nil 的值,除了救援块。

每个线程也是唯一的。它是当前的异常(English 库称它为 $ERROR_INFO),一旦被拯救它就会被重置为 nil,除非它被重新引发,然后它又回到当前的状态异常。

从一个没有其他行的文件中,我们可以看到 $!可见。

puts defined?($!)
puts $!.inspect  

irb(main):001:0> defined?($!)
=> "global-variable"
irb(main):002:0> $!
=> nil
irb(main):003:0>

并且在 IRB 中我们可以看到它已定义且可见。

这真的一点也不(或者更确切地说不应该)令人惊讶,因为 $ 指定它是“全局变量”,因此是全局可见的。

我没能找到它不可见的地方。即使在 BasicObject 中,它也是可见的。

irb(main):001:0> class BasicObject
irb(main):002:1>   def is_it_visible
irb(main):003:2>     defined?($!)                                                                                                 
irb(main):004:2>   end                                                                                                            
irb(main):005:1> end                                                                                                              
=> :is_it_visible
irb(main):006:0> BasicObject.allocate.is_it_visible
=> "global-variable"
irb(main):007:0>

我应该补充一点,它也是“只读”变量之一。尝试分配给它会导致 NameError 并显示一条消息,说明它是一个只读变量。