为什么Box smallBox =作用域!Box(); 是D中的BUG吗?

min*_*als 1 d

在“用D编程”一书中的“ 销毁和作用域 ”一章中,作者写道,使用作用域时应格外小心,因为如果在左侧指定了实际的类类型,就会引入一个错误。

Box c = scoped!Box();
Run Code Online (Sandbox Code Playgroud)

在该定义中,c不是代理对象;而是按照程序员的定义,是引用封装对象的类变量。不幸的是,在右侧构造的代理对象在构造它的表达式的结尾处终止。结果,在程序中使用c将是一个错误,可能会导致运行时错误。

这样的

Box smallBox = scoped!Box(); // BUG!
auto smallBox = scoped!Box(); // works fine
const smallBox = scoped!Box(); // works fine
Run Code Online (Sandbox Code Playgroud)

给出的解释对我来说有点高层次,因为它与由编译器推断出的类型有何auto smallBox不同Box smallBox?显式类型规范和D编译器之间的区别是什么,以至于它允许作用域代理结构提前终止对象?

Ada*_*ppe 5

一般来说,编译器会尝试将右侧的类型转换为与声明中左侧的类型匹配的类型。双方已经具有特定的类型-左侧实际上不会影响右侧的代码成为其他类型-只是它将转换。编译器将尝试进行尽可能少的转换以匹配左侧,并在不可能的情况下发出错误。

auto a = x;
Run Code Online (Sandbox Code Playgroud)

在这里,auto没有任何限制,因此的类型a与的类型相同x,因此无需进行转换。这是类型推断的最基本情况。

const a = x;
Run Code Online (Sandbox Code Playgroud)

在此,左侧为const,但在其他方面不受限制。因此,编译器将尝试将x的类型转换为,const而无需进一步更改。这是稍微复杂一些的类型推断,但仍然非常简单。

Box a = x;
Run Code Online (Sandbox Code Playgroud)

但是在这里,左侧是专门键入的Box。因此,无论如何x,编译器都会尝试将其专门转换为Box。这可能需要在alias this右侧类型内调用各种用户定义的转换,或者也可能执行隐式转换。

让我们具体点:

byte a;
auto x = a; // x is `byte`, just like a
const y = a; // y is now `const(byte)`, applying const to a's type
int z = a; // z is always an int, now a is converted to it.
Run Code Online (Sandbox Code Playgroud)

在这种情况下za被隐式转换为int。这是允许的,所以没有错误,但是现在za是不同的了。您会在基类和接口上看到类似的内容:

class A {}
class B : A {}

auto one = new B(); // one is type B
A two = new B(); // two is now of type A, the B object got converted to the base class A
Run Code Online (Sandbox Code Playgroud)

使用byteint和类,这基本上可以按预期工作。字节和整数基本上是同一件事,并且类保留运行时类型标记以记住它们的真实身份。

但是,使用结构会导致某些信息丢失。

struct A {}
struct B { A a; alias a this; }
Run Code Online (Sandbox Code Playgroud)

该结构B现在可以隐式转换为A...了,但是它只是通过返回一个单独的成员(a),而其余的都可以实现B

B b;
A a = b; // the same as `A a = b.a;`, it only keeps that one member in `a`
Run Code Online (Sandbox Code Playgroud)

这就是scoped内部的作用。看起来像这样:

struct Scoped(Class) {
     Class c;
     alias c this;
     ~this() { destroy(c); } // destructor also destroys child object
}
Run Code Online (Sandbox Code Playgroud)

那条alias this神奇的线允许它转换回Class类型...但是这样做是通过只返回一个引用成员,而放弃其余的Scoped,这(通过Scoped的目的定义)意味着它已经消失并破坏了Class的过程中。因此,您将获得对销毁对象的引用,这是他们警告的错误。