ruby 即使我已经为常量设置了自动加载,为什么在常量被删除时引发NameError?

b5lpy0ml  于 2023-01-12  发布在  Ruby
关注(0)|答案(1)|浏览(95)

下面的代码:

module P; end

P.autoload(:Foo, "#{__dir__}/foo.rb")
P::Foo.new.foo # works well

P.send(:remove_const, :Foo)
P::Foo.new.foo # raising error

我已经为P::Foo设置了autoload,但是第二次它不起作用。为什么和如何?
即使我重置autoload,它仍然不工作:

P.send(:remove_const, :Foo)
P.autoload(:Foo, "#{__dir__}/foo.rb")
P::Foo.new.foo # raising error
pgccezyw

pgccezyw1#

根据Module#autoload的文件:
注册要在 mod 的命名空间中第一次访问 module(可能是字符串或符号)时加载的文件名(使用Kernel::require)。
根据Kernel#require的文件:
加载给定的name,如果成功则返回true,如果功能已加载则返回false
您首先调用了P::Foo,它通过Kernel#require“自动加载”了“#{dir}/foo.rb”文件。然后您删除了常量P::Foo(在该文件中定义),但该特性已经加载,因此后续调用不会尝试并再次要求它,因为Kernel.require("#{__dir__}/foo.rb") #=> false
这与明确要求相同,例如
p/foo.rb

module P
  class Foo
    def foo; end
  end 
end

p.rb

module P; end 
require './p/foo' #=> true 

P::Foo.new.foo # works well

P.send(:remove_const, :Foo)

require './p/foo' #=> false
P::Foo.new.foo # raising error

如果你想“强制”重载那个文件,你可以调用Kernel#load

相关问题