2010-05-19 29 views
27

我想知道有什么区别以下两个模块红宝石(和Rails)嵌套的模块语法

# First Example 
module Parent 
    module Child 
    end 
end 

# Second Example 
module Parent::Child 
end 

使用第二方法之间,它看起来好像父模块必须预先定义,否则我得到一个'未初始化的常量'错误

鉴于此,定义这样的模块的首选方法,然后添加嵌套的孩子与重新gard语法和文件结构(即。文件夹等)。参考Rails的方式将不胜感激。

这两个例子对于所有意图和目的是否等同?

回答

31

在第一个示例中,它定义了Parent模块,然后是Child模块。第二个例子,如您所说,必须事先定义Parent模块。以牺牲一行代码为代价,您可以确保通过使用第一个示例嵌套到的模块始终将被定义。

对于Rails的例子,让我们看看到railties/lib中/导轨/ engine.rb文件,该文件re-opens the Rails module,然后它里面defines an Engine class。里面的类

class Rails::Engine 

但是,相反也许上面,或许说也为清晰起见的原因,该模块最初定义,那么:这可能已经完成与简单。

+1

一个重要的提示是@banister提到的 - 对常量的访问是不同的。 – thomthom 2012-08-07 13:43:43

7

一般来说,除非可以绝对确定Parent已经存在,否则不需要使用模块Parent :: Child语法来定义模块。如果定义了父模块,则只能使用::语法定义子模块。在你的例子中,如果你做了以下操作,你将不会得到未初始化的常量错误。

module Parent 
end 

module Parent::Child 
end 
13

我更喜欢第二种方法(如果确定Parent已经定义),因为它看起来更干净,当嵌套非常深时。

然而,第一种方法有一些优点,一个尚未讨论的是嵌套模块可以访问封闭模块中的任何词汇可用常量。

2

看来,班尼斯特的回答也是这种现象的原因:

ruby-1.9.2-p290 :001 > module A; module A; A.ancestors; end; end 
=> [A::A] 
ruby-1.9.2-p290 :002 > module A::A; A.ancestors; end 
=> [A] 

内部模块一个是外模块A内恒定的,因此使用第二种方法是不可见的。

编辑我之前的评论:

这在“Ruby编程语言”(第一版)的7.9“常量查找”解释。这里的相关部分是Module.nesting,它不包含第二个示例中的外部模块,因此A只能在全局范围中找到。