在D中,函数也可以作为一个函数的参数:
void doSomething(int function(int, int) doer) {
// 调用参数传过来的函数
doer(5,5);
}
doSomething(add); // 用全局的 `add` 函数作为参数
// add 函数需要两个参数
doer
可以像其他函数调用那样调用。
上面的例子使用 function
类型,它其实就是一个独立的函数指针。下面,我们要调用成员函数或本地函数,那么就要使用委托(delegate
)了 . 它也是个函数指针,但是带着上下文(或者叫 enclosure ),在其他语言中也叫做 closure 闭包。例如,对于类的成员函数,委托(delegate
) 既包含在这个函数的指针,也包含当前对象的引用(指针)。在函数内创建的委托 (delegate
),包含当前函数的上下文,D 编译器会把委托需要的上下文复制到堆中保证内存安全,并在委托里引用这块内存区域。
void foo() {
void local() {
writeln("local");
}
auto f = &local; // f 是 delegate() 类型
}
同样的 doSomething
用委托(delegate
)做参数,这样声明:
void doSomething(int delegate(int,int) doer);
delegate
和 function
不能混用. 标准库中有提供
std.functional.toDelegate
去转换一个 function
到 delegate
.
函数可以当作变量和传递给其他函数,对于每个函数起名就比较困难,所以 D 允许匿名函数和单行的 lambdas 。
auto f = (int lhs, int rhs) {
return lhs + rhs;
};
auto f = (int lhs, int rhs) => lhs + rhs; // Lambda - 内部会自动转换成上面那样
在标准库中,也可以把字符串当作函数去传给模板。 例如,这个例子使用叠加(reducer):
[1, 2, 3].reduce!`a + b`; // 6
字符串函数只支持 一个 和 两个_ 参数的函数,使用字符 a
作为第一个参数,使用字符 b
作为第二个参数.