混入
混入(Mixins) 意味着用不同的编程语言表达的不同的事物。 在D中,一个混入从一个 模版声明 的过程体内提取一个任意的声明集合,并将它们插入到当前的上下文中。模板混入: mixin 模板标志符 ; mixin 模板标志符 混入标志符 ; mixin 模板标志符 !( 模版参数列表 ) ; mixin 模板标志符 !( 模版参数列表 ) 混入标志符 ; 混入标志符: 标志符
TemplateMixin: mixin TemplateIdentifier ; mixin TemplateIdentifier MixinIdentifier ; mixin TemplateIdentifier !( TemplateArgumentList ) ; mixin TemplateIdentifier !( TemplateArgumentList ) MixinIdentifier ; MixinIdentifier: Identifier模版混入 可以出现在模块、类、结构、联合以及语句的声明列表中。 模板标志符 是一个 模版声明 。如果 模版声明 没有参数,就可以使用不带 !( 模版参数列表 ) 的混入形式。
不像模板具现化,模板混入的过程体在混入所在的作用域内计算,而不是在定义模板声明的地方。这等价于使用剪切和粘贴将模版的过程体插入混入的位置。这对注入参数化的‘样板文件’是有用的,同时对创建模板化嵌套函数也很有用,而正常情况下是不可能具现化嵌套函数的。
template Foo() { int x = 5; } mixin Foo; struct Bar { mixin Foo; } void test() { printf("x = %d/n", x); // 打印出 5 {
Bar b; int x = 3; printf("b.x = %d/n", b.x); // 打印出 5 printf("x = %d/n", x); // 打印出 3 { mixin Foo; printf("x = %d/n", x); // 打印出 5 x = 4; printf("x = %d/n", x); // 打印出 4 } printf("x = %d/n", x); // 打印出 3 } printf("x = %d/n", x); // 打印出 5 }混入可以被参数化:
template Foo(T) { T x = 5; } mixin Foo!(int); // 创建类型为 int 的 x混入可以可以为类添加虚函数:
template Foo() { void func() { printf("Foo.func()/n"); } } class Bar { mixin Foo; } class Code : Bar { void func() { printf("Code.func()/n"); } } void test() { Bar b = new Bar(); b.func(); // 调用 Foo.func() b = new Code(); b.func(); // 调用 Code.func() }混入在它们出现的地方被求值,而不是在模板声明的地方:
int y = 3; template Foo() { int abc() { return y; } } void test() { int y = 8; mixin Foo; // 使用的是局部的 y ,而不是全局的 y assert(abc() == 8); }混入可以使用别名参数来参数化符号:
template Foo(alias b) { int abc() { return b; } } void test() { int y = 8; mixin Foo!(y); assert(abc() == 8); }这个例子使用了一个混入来为任意语句实现一个泛型 Duff's Device(在这里,那个语句采用粗体表示)。在生成一个嵌套函数的同时也生成了一个委托文字量,他们会通过编译器内联:
template duffs_device(alias id1, alias id2, alias s)
{
void duff_loop()
{
if (id1 < id2)
{
typeof(id1) n = (id2 - id1 + 7) / 8;
switch ((id2 - id1) % 8)
{
case 0: do { s();
case 7: s();
case 6: s();
case 5: s();
case 4: s();
case 3: s();
case 2: s();
case 1: s();
} while (--n > 0);
}
}
}
}
void foo() { printf("foo/n"); }
void test()
{
int i = 1;
int j = 11;
mixin duffs_device!(i, j, delegate { foo(); } );
duff_loop(); // 执行 foo() 10 次
}
混入作用域
混入中的声明被‘导入’到周围的作用域中。如果混入和其周围的作用域中有相同的名字,周围的作用域中的声明将覆盖混入中的那个声明:int x = 3; template Foo() { int x = 5; int y = 5; } mixin Foo; int y = 3; void test() { printf("x = %d/n", x); // 打印出 3 printf("y = %d/n", y); // 打印出 3 }如果两个不同的混入被放入同一个作用域,并且他们中定义了同名的声明,就会出现模棱两可的错误:
如果一个混入中有 混入标志符 ,它可以用来消除歧义:template Foo()
{
int x = 5;
}
template Bar()
{
int x = 4;
}
mixin Foo;
mixin Bar;
void test()
{
printf("x = %d/n", x); // 错误,x 模棱两可
}
int x = 6; template Foo() { int x = 5; int y = 7; } template Bar() { int x = 4; } mixin Foo F; mixin Bar B; void test() { printf("y = %d/n", y); // 打印出 7 printf("x = %d/n", x); // 打印出 6 printf("F.x = %d/n", F.x); // 打印出 5 printf("B.x = %d/n", B.x); // 打印出 4 }混入有其自身的作用域,尽管声明会被外围的声明覆盖:
int x = 4; template Foo() { int x = 5; int bar() { return x; } } mixin Foo; void test() { printf("x = %d/n", x); // 打印出 4 printf("bar() = %d/n", bar()); // 打印出 5 }