模 块 2.014

模块:
模块声明 多个声明定义
多个声明定义

多个声明定义:
单个声明定义
单个声明定义 多个声明定义

单个声明定义:
属性指示符
导入声明
枚举声明
类声明
接口声明
聚集声明
单个声明
构造函数
析构函数
不变量
单元测试
静态构造函数
静态析构函数
Debug规范
Version规范
Mixin声明
;

模块同源文件是一一对应的。模块名就是去掉路径和扩展名的文件名。

模块自动为它的内容提供一个名字空间。模块跟类有一点相像,不同之处是:

• 每个模块只有一个实例,并且它是静态分配的。
• 模块没有虚函数表。
• 模块不能继承,它们没有父模块,等等。
• 每个文件只有一个模块。
• 模块的符号可以导入。
• 模块总是 在全局作用域内编译,并且不受周围的特征或其它修饰符影响。

多个模块可以组织成一个结构,叫做“包(packages)”。

模块提供了以下几种担保:

• 模块导入的顺序并不会对语义产生什么影响。
• 一个模块的语义不会被那些导入它的模块所影响。
• 如果一个模块 C 导入了模块 A 和 B,那么任何对 B 的修改都不会隐式地更改在模
块 C 里的跟 A 相独立的代码。


2.1 模块声明

“模块声明”指定了模块的名称和它所属的包。如果不指定,模块名将设定为去掉路径和扩
展名的文件名。

模块声明:
module 模块名 ;

模块名:
标识符
模块名 .标识符

最右面的“标识符”是模块所在的“包”。包在源文件路径中对应于目录名。
如果出现的话,“模块声明”按照语法位于源文件的开头,并且每个源文件只能有一个。
样例:
module c.stdio; // 这是模块 stdio,它位于 c 包中

按照惯例,包和模块名都为 小写。这是因为 包 和 模块名称 同操作系统中的目录名和文件名 一一对应,而许多文件系统不区分大小写。把所有的包和模块名称小写将减少在不同文件系统之间 迁移 项目时的问题。


2 导入声明

与文本的包含文件不同,D 通过使用“导入声明”直接导入符号:

导入声明:
import 导入列表 ;
static import 导入列表 ;

导入列表:
导入
导入绑定
导入 , 导入列表

导入:
模块名
模块别名标识符 = 模块名

导入绑定:
导入 :导入绑定列表

导入绑定列表:
导入绑定
导入绑定 , 导入绑定列表

导入绑定:
标识符
标识符 = 标识符

ModuleAliasIdentifier:
Identifier     2.014


有好几种形式的“导入声明”,从一般的到有细密纹理的(fine-grained)导入。

在“导入声明”里的声明顺序并不重要。

模块名(位于“导入声明”中)必须使用它们所处的那个包的名称来完整修饰。 它们就不
会被认为是相对于那个导入它们的模块。


3 基本导入

最简单的导入形式就是只做列出要被导入的模块:

import std.stdio; // 导入模块 stdio(自 std 包里)
import foo, bar; // 导入杠杆?? foo 和 bar
void main()
{
writefln("hello!\n"); // 调用 std.stdio.writefln
}

基本导入工作原理 就是:首先,在当前名字空间里搜索名字。如果没有找到,那么就到所有导入的模块里去查找。如果在这些导入模块中唯一找到一个,则使用它。
如果在多个导入模块里找到,则就出现错误。

module A;
void foo();
void bar();

module B;
void foo();
void bar();

module C;
import A;
void foo();
void test()
{ foo(); // C.foo() 被调用,它在搜索导入模块之前被找到
bar(); // A.bar() 被调用,因为搜索了导入模块
}

module D;
import A;
import B;
void test()
{ foo(); // 错误,是 A.foo() 还是 B.foo() 呢?
A.foo(); // 正确,调用 A.foo()
B.foo(); // 正确,调用 B.foo()
}

module E;
import A;
import B;
alias B.foo foo;
void test()
{ foo(); // 调用 B.foo()
A.foo(); // 调用 A.foo()
B.foo(); // 调用 B.foo()
}


4 公共导入

默认情况下,导入是“private(私有的)”。即表示,如果 A 导入模块 B,同时 B 又导入模块C,则 C 的名字是不会被搜索的。

一个导入可以特别地声明为“public(公共的)”,这时它会处理成这样:对于带有“导入声明”的模块,它的任何导入模块也会导入那些公共导入的模块。

module A;
void foo() { }

module B;
void bar() { }

module C;
import A;
public import B;
...
foo(); // 调用 A.foo()
bar(); // 调用 B.bar()

module D;
import C;
...
foo(); // 错误,foo() 未定义
bar(); // 正确,调用 B.bar()


5 静态导入

基本导入对于相对没有几个模块和导入的程序很有效。如果存在大量模块导入,则在各种不
同的导入模块里,名字 冲突 就会出现。

防止此种情况发生的一种方式就是使用 “静态导入(static imports)”。静态导入要求我们使用带 完整修饰 的名称来 引用 模块名。

static import std.stdio;
void main()
{
writefln("hello!"); // 错误,writefln 未定义
std.stdio.writefln("hello!"); // 正确,writefln 被完全限定
}


6 更名的导入

可以为某个导入给出本地名称;通过这个本地名称,所有对该模块符号的引用都必须进行限
定(be qualified with):

import io = std.stdio;
void main()
{
io.writefln("hello!"); // 正确,调用 std.stdio.writefln
std.stdio.writefln("hello!"); // 错误,std 未定义可能已经覆盖了 std.stdio 名称

writefln("hello!"); // 错误,writefln 未定义
}

更名的导入在处理很长的导入名时很方便。


7 选择性导入

特定的符号可以 特别 地从一个模块被导入,并被绑定到当前名字空间里。

import std.stdio : writefln, foo = writef;
void main()
{
std.stdio.writefln("hello!"); // 错误,std 未定义

writefln("hello!"); // 正确,writefln 被绑定到当前名字空间

writef("world"); // 错误,writefln 未定义

foo("world"); // 正确,调用 std.stdio.writef()

fwritefln(stdout, "abc"); // 错误,writefln 未定义
}

static 不能跟选择性导入一起使用。


8 更名 的且带 选择性 的导入

更名的且带选择性的导入被组合的情形:

import io = std.stdio : foo = writefln;
void main()
{
writefln("bar"); // 错误,writefln 未定义

std.stdio.foo("bar"); // 错误,foo 被绑定到当前名字空间

std.stdio.writefln("bar"); // 错误,std 未定义

foo("bar"); // 错误,foo 被绑定到当前名字空间,
// FQN 不需要

io.writefln("bar"); // 正确,io=std.stdio 将在当前名字空间里的名称 io
// 绑定来引用整个模块

io.foo("bar"); // 错误,foo 被绑定到当前名字空间,
// 而 foo 不是 io 的成员


9 模块作用域运算符

有些时候,有必要重写通常的词法作用域规则以访问被局部名称 掩盖 的名称。可以用 全局作用域 运算符‘.’ 达到这个目的,全局运算符位于标志符之前:
int x;
int foo(int x)
{
if (y)
return x; // 返回的是 foo.x,而非全局的 x
else
return .x; // 返回全局的 x}

前导的‘.’意味着在 模块作用域 级别 查找名称。


10 静态构造 和 析构

静态构造函数 是用来在 main() 之前 运行 的 初始化模块或类的代码。静态析构函数是在 main() 返回 之后 执行的代码,通常用来 释放 系统资源。

在一个模块里可以有 多个 静态构造函数 和 静态析构函数。静态构造函数的是以词法顺序运行的,而静态析构函数 则是以词法 相反 的顺序运行。

10.1 静态构造 的顺序

静态初始化的顺序 隐式 地由模块内的 import 声明的 顺序 决定。每个模块都会在它所依赖的模块 之后 调用自己的静态构造函数。

除了这条规则以外,模块静态构造函数的执行顺序是不定的。

导入声明中的 循环 (循环依赖) 是允许的,只要不是两个模块都含有静态构造或析构函数就行。

如果违反这条规则会在运行时产生异常。

10.2 一个模块中 静态构造 的顺序

在模块内部,静态构造 会按照它们出现的 词法 顺序执行。

10.3 静态析构 的顺序

静态析构 将按照与构造函数 相反 的顺序执行。只有当模块的 静态构造函数 成功执行后,才会执行 静态析构函数。

10.4 单元测试的顺序

单元测试是以出现在 模块 里的 词法 顺序运行的。


11 Mixin 声明

Mixin声明:
mixin ( 赋值表达式 ) ;

赋值表达式 必须在编译时求值成一个 常量字符串。该字符串的 文本内容 必须要可编译成一
个 有效 的 多个声明 定义,而且同样地被编译。



。。。

你可能感兴趣的:(C++,c,C#,单元测试)