2013-07-11 42 views
7

根據使用的語法,爲什麼重新打開嵌套模塊會得到不同的結果?例如,這工作得很好:在Ruby中重新打開嵌套模塊異常

module A 
    module E 
    end 
end 
module A 
    module E 
    def E.e 
    end 
    end 
end 

但這:

module A 
    module E 
    end 
end 
module A::E 
    def E.e 
    end 
end 

給出了錯誤:

reopen.rb:6:in `<module:E>': uninitialized constant A::E::E (NameError) 
from reopen.rb:5:in `<main>' 

(有人指出這一點之前,一個解決方法是使用self代替在定義Ee時的模塊名稱,但這不是這篇文章的要點)。

+2

那麼,有什麼問題? –

+0

公平點 - 改寫。 –

回答

4

module關鍵字設置名稱空間上下文,該名稱空間上下文被檢查以引用現有的模塊名稱。這些名稱空間然後從內到外進行搜索以解析對Module(和Class)名稱的引用。

在你的第一個例子,它看起來你可能需要定義E.emodule E塊,但實際上你不:

module A 
    module E 
    end 
end 
module A 
    def E.e 
    end 
end 

兩個你的例子會發生什麼事是,紅寶石看當前命名空間,並嘗試<namespace>::E作爲模塊名稱。所以在這兩個例子中,它檢查的第一件事實際上是A::E::E,它不存在。然後它回落到下一個上下文。哪些地方的例子不同:在第一個例子中,它是A::E這是有效的,在第二個例子中,它只是E而不是。然後它拋出的錯誤與它檢查的名字有關。

+1

有趣。使用「嵌套」名稱創建非嵌套上下文的IMO模塊A :: E是一個錯誤。如果它相當於: '模塊A 模塊E ...' 我會說這將更接近於關於名稱空間的正常直覺。 –

+0

是的,它總是在'module'塊中創建一個單一的上下文。在這方面至少是自洽的。除了歷史原因外,我看不出任何其他原因,除了歷史原因外 - 甚至可能存在依賴於當前行爲的代碼 - 其中'E'和'A :: E'都被定義例如。 –

+0

夠公平的。也許在這裏提出這個問題可能會導致它滲透到未來版本的Ruby中。 –