模塊
模塊: 模塊聲明 多個聲明定義 多個聲明定義 多個聲明定義: 聲明定義 聲明定義 多個聲明定義 聲明定義: 特徵指示符 導入聲明 枚舉聲明 類聲明 接口聲明 聚集聲明 聲明 構造函數 析構函數 不變量 單元測試 靜態構造函數 靜態析構函數 調試規格 版本規格 ;
Module: ModuleDeclaration DeclDefs DeclDefs DeclDefs: DeclDef DeclDef DeclDefs DeclDef: AttributeSpecifier ImportDeclaration EnumDeclaration ClassDeclaration InterfaceDeclaration AggregateDeclaration Declaration Constructor Destructor Invariant Unittest StaticConstructor StaticDestructor DebugSpecification VersionSpecification ;模塊同源文件是一一對應的。模塊名就是去掉路徑和擴展名的文件名。
模塊自動爲它的內容提供一個名字空間。模塊有一點像類,不同之處是:
- 每個模塊只有一個實例,並且它是靜態分配的。
- 模塊沒有虛函數表。
- 模塊不能繼承,它們沒有父模塊,等等。
- 每個文件只有一個模塊。
- 模塊的符號可以導入。
- 模塊總是在全局作用域內編譯,並且不受周圍的特徵或其它修飾符影響。
模塊的聲明
模塊聲明 指定了模塊的名稱和它所屬的包。如果不指定,模塊名將設定爲去掉路徑和擴展名的文件名。模塊聲明: module 模塊名 ; 模塊名: 標誌符 模塊名 . 標誌符
ModuleDeclaration: module ModuleName ; ModuleName: Identifier ModuleName . Identifier最右面的 標誌符 是模塊所在的 包 。包在源文件路徑中對應於目錄名。
如果出現的話,模塊聲明 按照語法位於源文件的開頭,並且每個源文件只能有一個。
示例:
c.stdio;按照慣例,包和模塊名都爲小寫。這是因爲包和模塊名稱同操作系統中的目錄名和文件名一一對應,而許多文件系統不區分大小寫。把所有的包和模塊名稱小寫將減少在不同文件系統之間遷移項目時的問題。
導入聲明
與文本的包含文件不同,D 通過 import 聲明直接導入符號:導入聲明: import 模塊名列表 ; 模塊名列表: 模塊名 模塊名 , 模塊名列表
ImportDeclaration: import ModuleNameList ; ModuleNameList: ModuleName ModuleName , ModuleNameList最右邊的 標誌符 是模塊名稱。模塊中的最上層作用域將同當前的作用域合併。
示例:
std.c.stdio; foo, bar;
作用域和模塊
每個模塊都有自己的名稱空間。當一個模塊被導入另一個模塊時,默認的行爲是它的所有最上層聲明都在當前模塊中有效。模棱兩可是非法的,可以通過顯式引用解決,方法是通過模塊名引用。例如,假設有下面的模塊:
Module foo x = 1; y = 2; Module bar y = 3; z = 4;然後:
foo; ... q = y;並且:
foo; y = 5; q = y;以及:
foo; bar; q = y;還有:
foo; bar; q = bar.y;如果導入是私有的,例如:
abc; def;則當其他模塊導入 abc 時不會搜索 def 。
模塊作用域運算符
有些時候,有必要重寫通常的詞法作用域規則以訪問被局部名稱掩蓋的名稱。可以用全局作用域運算符‘.’達到這個目的,全局運算符位於標誌符之前:x; foo( x) { (y) x; .x; }前導的‘.’意味着在模塊作用域級別查找名稱。
靜態構造和析構
靜態構造函數是用來在 main() 之前運行的初始化模塊或類的代碼。靜態析構函數是在 main() 返回之後執行的代碼,通常用來釋放系統資源。靜態構造的順序
靜態初始化的順序隱式地由模塊內的 導入 聲明的順序決定。每個模塊都會在它所依賴的模塊之後調用自己的靜態構造函數。除了這條規則以外,模塊靜態構造函數的執行順序是不定的。導入聲明中的循環(循環依賴)是允許的,只要不是兩個模塊都含有靜態構造或析構函數就行。如果違反這條規則會在運行時產生異常。