是否可以为子模块提供与顶级类相同的名称?

时间:2011-06-06 15:41:13

标签: ruby class namespaces module

背景:

这是问题所在,简化为最小的例子:

# bar.rb
class Bar
end

# foo/bar.rb
module Foo::Bar
end

# foo.rb
class Foo
  include Foo::Bar
end

# runner.rb
require 'bar'
require 'foo'
➔ ruby runner.rb
./foo.rb:2: warning: toplevel constant Bar referenced by Foo::Bar
./foo.rb:2:in `include': wrong argument type Class (expected Module) (TypeError)
    from ./foo.rb:2
    from runner.rb:2:in `require'
    from runner.rb:2

3 个答案:

答案 0 :(得分:19)

出色;您的代码示例非常清晰。你所拥有的是一个花园式的循环依赖,被Ruby的范围分辨算子的特殊性所掩盖。

当你运行Ruby代码require 'foo'时,ruby会找到foo.rb并执行它,然后找到foo/bar.rb并执行它。因此,当Ruby遇到您的Foo类并执行include Foo::Bar时,它会在类Bar中查找名为Foo的常量,因为这是Foo::Bar所表示的。当找不到它时,它会在其他封闭范围内搜索名为Bar的常量,并最终在顶层找到它。但 Bar是一个类,因此不能include d。

即使您能说服requirefoo/bar.rb之前运行foo.rb,也无济于事; module Foo::Bar表示“找到常量Foo,如果它是类或模块,则开始在其中定义名为Bar的模块”。 <{1}}尚未创建,因此需求仍然会失败。

Foo重命名为Foo::Bar也无济于事,因为名称冲突最终没有错。

那么可以你做什么?在高层次上,你必须以某种方式打破这个循环。最简单的方法是将Foo::UserBar分为两部分,如下所示:

Foo

希望这有帮助。

答案 1 :(得分:2)

以下是演示此行为的更简单示例:

class Bar; end
class Foo
  include Foo::Bar
end

输出:

warning: toplevel constant Bar referenced by Foo::Bar
TypeError: wrong argument type Class (expected Module)

这里更加微不足道:

Bar = 0
class Foo; end
Foo::Bar

输出:

warning: toplevel constant Bar referenced by Foo::Bar

解释很简单,没有错误:Bar中没有Foo,而Foo::Bar尚未定义。要定义Foo::Bar,必须先定义Foo。以下代码工作正常:

class Bar; end
class Foo
  module ::Foo::Bar; end
  include Foo::Bar
end

然而,有些事情对我来说是意想不到的。以下两个块的行为不同:

Bar = 0
class Foo; end
Foo::Bar

发出警告:

warning: toplevel constant Bar referenced by Foo::Bar

Bar = 0
module Foo; end
Foo::Bar

产生错误:

uninitialized constant Foo::Bar (NameError)

答案 2 :(得分:0)

这是另一个有趣的例子:

module SomeName
  class Client
  end
end

module Integrations::SomeName::Importer
  def perform
    ...
    client = ::SomeName::Client.new(...)
    ...
  end
end

产生:

block in load_missing_constant': uninitialized constant Integrations::SomeName::Importer::SomeName (NameError)

Ruby(2.3.4)只是发现它可以找到的第一个“SomeName”,而不是顶层。

解决它的方法是使用更好的模块/类嵌套(!!),或者使用Kernel.const_get('SomeName')

相关问题