2306d的闭包问题

原文
首先,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错误地拒绝不变环境到非限定环境的转换.

你可能感兴趣的:(dlang,d,d,闭包)