Ruby中的命名空间混淆

时间:2013-11-26 19:59:11

标签: 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

你能解释一下原因吗?

1 个答案:

答案 0 :(得分:4)

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

 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>'