新特性:
1、给委托增加ptr属性,指向委托所绑定的对象。
这是一个语法糖,dg.ptr被转化为cast(void*)dg,它只能作右值,所以除了能读取它以外,在语法上禁止对它赋值。要想把委托绑定到不同的对象,你只能自己实现:
class Foo{
int foo;
public:
this(int foo){
this.foo = foo;
}
void bar(){
writefln(foo);
}
}
void main(){
alias void delegate() DG;
DG dg = &(new Foo(1)).bar;
Foo[10] foos;
foreach(int i, inout Foo foo; foos){
foo = new Foo(i);
}
void** ptr = cast(void**)&dg;
foreach(Foo foo; foos){
*ptr = cast(void*)foo;
dg();
}
}
这种方式也不是我们所希望的,一般来说委托绑定到多个对象时,因为是取到某成员函数指针,再进行绑定。比如模拟一个ActiveSupport所扩展的一个ruby.Array#map用法:
import std.stdio;
class Foo{
int foo;
public:
this(int foo){
this.foo = foo;
}
void bar(){
writefln(foo);
}
}
class Array(T){
private:
T[] data;
public:
this(T[] data){
this.data = data[0 .. length];
}
void map(void function() func){
void delegate() dg;
void** funcPtr = cast(void**)&dg + 1;
*funcPtr = func;
void ** ptr = cast(void**)&dg;
foreach(T v; data){
*ptr = cast(void*)v;
dg();
}
}
}
void main(){
auto arr = new Array!(Foo)([new Foo(1), new Foo(2), new Foo(3)]);
arr.map(&Foo.bar);
}
是的,delegate内部保存了2个指针,所以我们可以容易地hack它。
[注:上面的main函数中数组直接量赋给栈对象也是这个版本中新增的内容,显然只能用于static对象是很鸡肋的。这里简单带过不提。]
[注:上面这个map的模拟并不是ActiveSupport的map扩展的全部用途,那个map还是收集返回值,这里只演示调用语法。ActiveSupport中扩展的map调用语法是map(&:to_s),就可以收集到数组中所有元素调用to_s后的返回值。]
2、给内嵌内的实例增加outer属性,指向外层对象。
import std.stdio;
class Outer{
class Inner{}
this(){
Inner inner = new Inner;
inner.outer.foo();
}
void foo(){
writefln("foo");
}
}
void main(){
Outer outer = new Outer;
}
这个特性可能应用并不是很广吧。
3、mixin多个析构函数。
template A(){
this(){
}
~this(){
writefln("A::~A()");
}
}
template B(){
~this(){
writefln("B::~B()");
}
}
class C{
mixin A;
mixin B;
}
void main(){
C c = new C;
delete c;
}
这些析构函数会和mixin相反的顺序执行。我不明白的是,为什么不让mixin多个构造函数?为何不让这些构造函数晚于被mixin的类(上面的C类)的构造函数,并按mixin进来的顺序执行?