原文
首先,D
的闭包是个好主意.我使用了C++
的成员函数指针;它们在语法
上很糟糕,但概念
很好,而闭包
更好.
D的闭包
有些问题,有些是明显
错误,有些是不应该不在
语言中的改进
.
不能调用某些闭包
这很奇怪,但这是真的
.
一个问题是常
和不变
目前没有扩展到闭包
环境.要求常和不变
的传递性时,这是个错误:
const(void delegate()) dg = &obj.method;
(因为按常
变量声明,)不应该可调用dg
:dg
获得的引用不应更改
它的环境,但不能保证dg
不会这样:方法不一定会用常
注解.
const(void delegate() const) dg = &obj.constMethod;
此DG
有个承诺不改变环境的常注解
;因此,可调用它.如果不是用常
(或不变)注解常方法(constMethod)
,则赋值
将不管用.
拒绝了一些有效且有用的转换
因为闭包
是紧密绑定的环境-函数
对,因此有不变
注解的闭包
应按可变
闭包隐式转换
:(因为被调
函数根本不会这样做,调用闭包
,或其他方式)重新注解,不改变不会更改环境
,且重新赋值
注解可变
闭包也不改变
这一点,因为不能单独赋值环境和函数指针
.
另一个应正常工作的是函数指针
到闭包
的转换
,事实上,因为函数指针
没有环境
,所以它的环境
是不变
的:
void f() @safe { writeln("Hello"); }
void delegate() @safe immutable dg = &f; //今天:是错误,解决方法:
//
void delegate() @safe immutable dg = () @trusted {void delegate() @safe immutable result = null;result.funcptr = cast(typeof(result.funcptr)) &f;return result;
}();
dg(); //(如期)打印"你好"
有以下序列:
void function() ->
void delegate() immutable ->
void delegate() const ->
void delegate()
第一个是值转换
,其他是引用转换
.
直接使用λ
时,第一个转换
有效,但当把λ
赋值给自动
变量,然后按参数传递给闭包类型
参数时,则不会转换.
推导环境限定符
这适合
闭包.(对对象-方法对
地址,该方法告诉了精确的限定符
).闭包有闭包或函数指针
类型,可以说,它应该有有最多保证
的类型(如,因此它推导
属性).
但有时,闭包不会推导
类型限定符.
int x;
auto dg = () => x;
pragma(msg, typeof(dg)); //int delegate() pure nothrow @nogc @safe
类型
没有错,只是缺少了:它缺少常
,因为闭包抓了x
,且在运行时
闭包不会改变x
.则为什么常
不应是它的属性
之一?不过,可显式地请求常
:
int x;
auto dg = () const => x;
pragma(msg, typeof(dg)); //int delegate() const pure nothrow @nogc @safe
它是否兑现
承诺?不:
int x;
auto dg = () const => x += 1; //为什么可以这样
注意,dg
是纯的.0
参数常纯
闭包不能影响值:
int x = 0;
assert(x == 0); //通过,为什么可以这样,int delegate() const pure nothrow @nogc @safe
auto dg = () const => x += 1; //
pragma(msg, typeof(dg)); //
dg();
assert(x == 1); //通过,但可能会因为优化而失败
不变
呢?
immutable int x;
auto dg = () => x;
pragma(msg, typeof(dg)); //不变(int) delegate() pure nothrow @nogc @safe
不变(整)
返回突出类型
,但这不是重点.有趣的是,dg
抓的所有事物(即x
)都是不变
的.可显式
要求不变:
immutable int x;
auto dg = () immutable => x;pragma(msg, typeof(dg)); //不变(整) 闭包() 不变 纯 不抛 @nogc @safe
只有在可隐式遗忘这些保证
,函数
而不是闭包
的推导和不变
的推导时才有意义.
无法表示某些类型
用类型构造器
属性,可表示闭包的底层函数
不得改变其环境,或环境
是完全不变的.
而应用构造类型器
至整个闭包类型
后,它可能会(相反:有时候应该
)不可用
,这很糟糕.
如果想表达不应重新赋值
闭包怎么办?表明:函数指针是常或不变
的(不重要),但环境
可任意.我知道它不常用,但有时有用.
如果按(dg.ptr,dg.funcptr)对
对待dg
闭包,好像dg.funcptr
是常
,而不管dg.ptr
(环境).
不可赋值
组件使双
不可赋值.完成.很容易.只有语言
没有概念
,也没有语法
.如果可以,语法可以是int delegate 常()
,同样与常(常(int)[])
与常(int[])
类型相同一样,常(整 闭包 常())
与常(整 闭包())
相同.
我认为不管用的原因
是函数和闭包
有不同调用约定
.为了允许把函数指针
转换为闭包
,编译器必须生成一个蹦床
.
关于环境
限定符,还存在以下问题,这里:
"std.functional.toDelegate"
可生成蹦床
,这里.
但是,它会生成非限定
环境:
import std.functional;
void foo()@safe{}
void main(){void delegate()immutable dg=toDelegate(&foo); //错误
}
它必须这样,因为DMD
错误地拒绝
从不变
环境到非限定环境
的转换.