ruby - Ruby 中的命名空间困惑

标签 ruby module

我正在使用 Ruby 模块。

这工作得很好:

module Mod1
  def hello
    "Hello from mod 1"
  end
end

module Mod2
  def hello
    "Hello from mod 2"
  end
end

class Foo
  include Mod1
  include Mod2
end

f = Foo.new
puts f.hello
# output: "Hello from mod 2"

这不起作用:

module Mod1
  def hello
    "Hello from mod 1"
  end
end

module Mod2
  def hello
    "Hello from mod 2"
  end
end

class Foo < BasicObject
  include Mod1
  include Mod2
end

f = Foo.new
puts f.hello
# output: in `<class:Foo>': uninitialized constant Foo::Mod1 (NameError)

这有效:

module Mod1
  def hello
    "Hello from mod 1"
  end
end

module Mod2
  def hello
    "Hello from mod 2"
  end
end

class Foo < BasicObject
  include ::Mod1
  include ::Mod2
end

f = Foo.new
puts f.hello

您能解释一下原因吗?

最佳答案

在 Ruby 的对象模型中,Object 是在 BasicObject 下定义的。因此,默认情况下,您将在 Object 中定义的任何内容都无法从 BasicObject 访问。

 Object.superclass # => BasicObject

现在,您的类 FooBasicObject 的子类,因此它位于 Object 类的顶部。因此,这些模块对于 Foo 类来说是不可见的。因为模块 Mod1Mod2 是在 Object 类中定义的。您将在顶层定义的任何内容都将进入 Object 类的范围,这就是 Ruby 顶层的定义方式。

您的代码的最后一部分正在工作,因为您明确地将常量路径指定为 include::Mod1include::Mod2::Mod2 表示您说该模块是在 Object 类中定义的,请在类中为我带来它。

但是代码第二部分的情况并非如此,因此 Foo 无法找到模块,因为您没有给它路径,就像上面的部分一样。

第一部分正在工作,因为模块是在 Object 范围中定义的,并且类 FooObject 的子类,因此只有 include Mod1`include Mod2 确实按预期工作。

以下是类似的用例,可能会让您对此有所了解:

这里没有错误

class B 
    module F;end
end

class A < B
    include F
end

这里出错

class B
  include F
end

class A < B
  module F;end
end
# ~> -:2:in `<class:B>': uninitialized constant B::F (NameError)
# ~>  from -:1:in `<main>'

关于ruby - Ruby 中的命名空间困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20226754/

相关文章:

ruby-on-rails - Ruby on Rails - 下拉菜单

perl - 使用 Perl 创建包

Ruby `when' 关键字不在 case 语句中使用 ==。它有什么用?

ruby - 可以在step_definitions和PageObject方法中共享@variable吗?

JavaScript 命名空间模式

javascript - 在 Ionic 3 中使用 Http 获取 JSON 数据

objective-c - 如何确定 Xcode 是否支持模块?

javascript - 使用嵌套回调设置js模块的属性

ruby-on-rails - 数组在递归函数中的奇怪行为

ruby - Sinatra cookie 未按预期运行