知识若不分享 实在没有意义 http://www.d-programming-language-china.org 20070416
点击下面网址查看原文:
http://www.d-programming-language-china.org
by: uFramer D语言论坛 http://www.d-programming-language-china.org
from: http://www.digitalmars.com/d/module.html
version: 基于D 1.012 (Apr 12, 2007)
D语言模块定义
模块:
模块声明 多个声明定义
多个声明定义
多个声明定义:
声明定义
声明定义 多个声明定义
声明定义:
特征指示符
导入声明
枚举声明
类声明
接口声明
聚集声明
声明
构造函数
析构函数
不变量
单元测试
静态构造函数
静态析构函数
调试规格
版本规格
混入声明
;
Module:
ModuleDeclaration DeclDefs
DeclDefs
DeclDefs:
DeclDef
DeclDef DeclDefs
DeclDef:
AttributeSpecifier
ImportDeclaration
EnumDeclaration
ClassDeclaration
InterfaceDeclaration
AggregateDeclaration
Declaration
Constructor
Destructor
Invariant
UnitTest
StaticConstructor
StaticDestructor
DebugSpecification
VersionSpecification
MixinDeclaration
;
模块同源文件是一一对应的。模块名就是去掉路径和扩展名的文件名。
模块自动为它的内容提供一个名字空间。模块有一点像类,不同之处是:
每个模块只有一个实例,并且它是静态分配的。
模块没有虚函数表。
模块不能继承,它们没有父模块,等等。
每个文件只有一个模块。
模块的符号可以导入。
模块总是在全局作用域内编译,并且不受周围的特征或其它修饰符影响。
多个模块可以组织成一个结构,叫做包 。
模块的声明
模块声明 指定了模块的名称和它所属的包。如果不指定,模块名将设定为去掉路径和扩展名的文件名。
模块声明:
module 模块名 ;
模块名:
标志符
模块名 . 标志符
ModuleDeclaration:
module ModuleName ;
ModuleName:
Identifier
ModuleName . Identifier
标志符 左边是模块所在的 包 。包在源文件路径中对应于目录名。
如果出现的话,模块声明 按照语法位于源文件的开头,并且每个源文件只能有一个。
示例:
module c.stdio; // 这是c包中的stdio模块
按照惯例,包和模块名都为小写。这是因为包和模块名称同操作系统中的目录名和文件名一一对应,而许多文件系统不区分大小写。把所有的包和模块名称小写将减少在不同文件系统之间迁移项目时的问题。( 本文出处: http://www.d-programming-language-china.org )
导入声明
通过 import 声明直接导入的符号知另外的模块同样可用:
导入声明:
import 模块名列表 ;
static import 模块名列表
模块名列表:
模块名
导入绑定
模块名 , 模块名列表
ImportDeclaration:
import ImportList ;
static import ImportList ;
ImportList:
Import
ImportBindings
Import , ImportList
Import:
ModuleName
ModuleAliasIdentifier = ModuleName
ImportBindings:
Import : ImportBindList
ImportBindList:
ImportBind
ImportBind , ImportBindList
ImportBind:
Identifier
Identifier =
有多种import 声明形式.
import声明的顺序并不重要。
ModuleNames in the ImportDeclaration must be fully qualified with whatever packages they are in. They are not considered to be relative to the module that imports them.
Basic Imports
简单的形式是导入列出的模块名:
import std.stdio; // 导入std包中的stdio模块
import foo, bar; // import modules foo and bar
void main()
{
writefln("hello!\n"); // calls std.stdio.writefln
}
模块导入的基本原理是,首先在当前名字空间搜索名字。找不到的话在imports模块中搜索,找到唯一名字就使用它,如果在多个模块中找到同样名字就引发错误。( 本文出处: http://www.d-programming-language-china.org )
module A;
void foo();
void bar();
module B;
void foo();
void bar();
module C;
import A;
void foo();
void test()
{ foo(); // C.foo() is called, it is found before imports are searched
bar(); // A.bar() is called, since imports are searched
}
module D;
import A;
import B;
void test()
{ foo(); // error, A.foo() or B.foo() ?
A.foo(); // ok, call A.foo()
B.foo(); // ok, call B.foo()
}
module E;
import A;
import B;
alias B.foo foo;
void test()
{ foo(); // call B.foo()
A.foo(); // call A.foo()
B.foo(); // call B.foo()
}
Public Imports
默认是导入是私有的,也就是模块A导入模块B,模块B导入模块C,在模块A里,模块C的名字不在搜索列表中。
声明为public的导入模块,导入本模块也就导入了public导入的模块。
下面是实例:
module A;
void foo() { }
module B;
void bar() { }
module C;
import A;
public import B;
...
foo(); // call A.foo()
bar(); // calls B.bar()
module D;
import C;
...
foo(); // error, foo() is undefined
bar(); // ok, calls B.bar()
Static Imports
当导入模块相对较少时,Basic imports足以胜任。如果导入模志很多,不同模块的名字碰撞,也就是同样名字在多个模块的情况就有可能发生。这时可以用static imports.
statia import需要用模块的全名来引用。( 本文出处: http://www.d-programming-language-china.org )
static import std.stdio;
void main()
{
writefln("hello!"); // error, writefln is undefined
std.stdio.writefln("hello!"); // ok, writefln is fully qualified
}
Renamed Imports
可以给引入模块一个本地名称,这时就必须这样引用模块:
import io = std.stdio;
void main()
{
io.writefln("hello!"); // ok, calls std.stdio.writefln
std.stdio.writefln("hello!"); // error, std is undefined
writefln("hello!"); // error, writefln is undefined
}
Renamed imports 在处理冗长导入模块名时很有用。
Selective Imports
从一个模块中只导入专门符号,并绑定到当前名字空间。( 本文出处: http://www.d-programming-language-china.org )
import std.stdio : writefln, foo = writef;
void main()
{
std.stdio.writefln("hello!"); // error, std is undefined
writefln("hello!"); // ok, writefln bound into current namespace
writef("world"); // error, writef is undefined
foo("world"); // ok, calls std.stdio.writef()
fwritefln(stdout, "abc"); // error, fwritefln undefined
}
static 不能和selective imports同时使用.
Renamed and Selective Imports
当renaming和selective importing联合使用时是这样:
import io = std.stdio : foo = writefln;
void main()
{
writefln("bar"); // error, writefln is undefined
std.stdio.foo("bar"); // error, foo is bound into current namespace
std.stdio.writefln("bar"); // error, std is undefined
foo("bar"); // ok, foo is bound into current namespace,
// FQN not required
io.writefln("bar"); // ok, io=std.stdio bound the name io in
// the current namespace to refer to the entire module
io.foo("bar"); // error, foo is bound into current namespace,
// foo is not a member of io
模块作用域运算符
有些时候,有必要重写通常的词法作用域规则以访问被局部名称掩盖的名称。可以用全局作用域运算符‘.’达到这个目的,全局运算符位于标志符之前:
int x;
int foo(int x)
{
if (y)
return x; // 返回 foo.x ,而不是全局的 x
else
return .x; // 返回全局的 x
}
前导的‘.’意味着在模块作用域级别查找名称。
静态构造和析构
静态构造函数是用来在 main() 之前运行的初始化模块或类的代码。静态析构函数是在 main() 返回之后执行的代码,通常用来释放系统资源。( 本文出处: http://www.d-programming-language-china.org )
1.1 静态构造的顺序
静态初始化的顺序隐式地由模块内导入 声明的顺序决定。每个模块都会在它所依赖的模块之后调用自己的静态构造函数。除了这条规则以外,模块静态构造函数的执行顺序是不定的。
导入声明中的循环(循环依赖)是允许的,只要不是两个模块都含有静态构造或析构函数就行。如果违反这条规则会在运行时产生异常。
1.2 一个模块中静态构造的顺序
在模块内部,静态构造会按照它们出现的词法顺序执行。
1.3 静态析构的顺序
静态析构将按照与构造函数相反的顺序执行。只有当模块的静态构造函数成功执行后,才会执行静态析构函数。
1.4 单元测试的顺序
在模块内部,单元测试会按照它们出现的词法顺序执行。
混入构造
MixinDeclaration:
mixin ( AssignExpression ) ;
The AssignExpression must evaluate at compile time to a constant string. The text contents of the string must be compilable as a valid DeclDefs, and is compiled as such.
参见:
http://www.digitalmars.com/d/expression.html#AssignExpression( 本文出处: http://www.d-programming-language-china.org )
( lastupdate:20070421 最新文章请访问http://www.d-programming-language-china.org )关于一大步成功社区:
yidabu提倡在交流中学习,在分享中提高
收集感兴趣的知识,写下心得,通过网络与别人一起分享
理解一点就实践一步,收获什么就分享什么,成功就是这样一点点一步步累积起来的
网络只是一个工具,只有自己身心提高才是实实在在的。d-programming-language-china.org为大家提供一个学习交流各种知识的平台