为什么Box smallBox=scoped!Box();虫子在D中吗?

为什么Box smallBox=scoped!Box();虫子在D中吗?,d,D,在“在D“书中编程”一章中,作者写道,在使用范围时应小心,因为如果在左侧指定实际的类类型,则会引入错误 Box c = scoped!Box(); 在该定义中,c不是代理对象;相反,正如程序员所定义的,类变量引用封装的对象。不幸的是,在右侧构造的代理对象在构造它的表达式的末尾终止。因此,在程序中使用c将是一个错误,可能导致运行时错误 以致 Box smallBox = scoped!Box(); // BUG! auto smallBox = scoped!Box(); // works fi

在“在D“书中编程”一章中,作者写道,在使用范围时应小心,因为如果在左侧指定实际的类类型,则会引入错误

Box c = scoped!Box();
在该定义中,c不是代理对象;相反,正如程序员所定义的,类变量引用封装的对象。不幸的是,在右侧构造的代理对象在构造它的表达式的末尾终止。因此,在程序中使用c将是一个错误,可能导致运行时错误

以致

Box smallBox = scoped!Box(); // BUG!
auto smallBox = scoped!Box(); // works fine
const smallBox = scoped!Box(); // works fine

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

一般来说,编译器会尝试转换右侧的类型,以匹配声明中左侧的类型。两边都已经有了一个特定的类型-左边实际上不会影响右边的代码成为不同的类型-只是它会转换。编译器将尽可能少地进行转换以匹配左侧,如果不可能,则会发出错误

auto a = x;
这里,
auto
没有限制,因此
a
的类型与
x
的类型相同,因此不需要转换。这是最基本的类型推断

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

Box a = x;
但在这里,左侧是专门键入的
。因此,无论
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.
z
的情况下,
a
被隐式转换为
int
。这是允许的,所以没有错误,但是
z
a
现在是不同的东西。您可以在基类和接口中看到类似的情况:

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
对于
byte
int
,以及类,这基本上可以按预期工作。字节和整数基本上是一样的,类保留一个运行时类型标记以记住它们的真实身份

但是使用structs时,可能会导致某些信息丢失

struct A {}
struct B { A a; alias a this; }
结构
B
现在可以隐式转换为类型
A
。。。但是它只返回一个单独的成员(
a
),而将
B
的其余成员留在后面

B b;
A a = b; // the same as `A a = b.a;`, it only keeps that one member in `a`
这就是
作用域
在内部所做的。它看起来像这样:

struct Scoped(Class) {
     Class c;
     alias c this;
     ~this() { destroy(c); } // destructor also destroys child object
}

别名此
魔线允许它转换回类类型。。。但是它只返回了一个引用成员,而放弃了其余的
作用域
,根据作用域用途的定义,这意味着它消失了,并在过程中破坏了类的内存。因此,您只剩下一个对已销毁对象的引用,这就是他们警告的bug。

一般来说,编译器将尝试转换右侧的类型,以匹配声明中左侧的类型。两边都已经有了一个特定的类型-左边实际上不会影响右边的代码成为不同的类型-只是它会转换。编译器将尽可能少地进行转换以匹配左侧,如果不可能,则会发出错误

auto a = x;
这里,
auto
没有限制,因此
a
的类型与
x
的类型相同,因此不需要转换。这是最基本的类型推断

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

Box a = x;
但在这里,左侧是专门键入的
。因此,无论
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.
z
的情况下,
a
被隐式转换为
int
。这是允许的,所以没有错误,但是
z
a
现在是不同的东西。您可以在基类和接口中看到类似的情况:

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
对于
byte
int
,以及类,这基本上可以按预期工作。字节和整数基本上是一样的,类保留一个运行时类型标记以记住它们的真实身份

但是使用structs时,可能会导致某些信息丢失

struct A {}
struct B { A a; alias a this; }
结构
B
现在可以隐式转换为类型
A
。。。但是它只返回一个单独的成员(
a
),而将
B
的其余成员留在后面

B b;
A a = b; // the same as `A a = b.a;`, it only keeps that one member in `a`
这就是
作用域
在内部所做的。它看起来像这样:

struct Scoped(Class) {
     Class c;
     alias c this;
     ~this() { destroy(c); } // destructor also destroys child object
}
别名此
魔线允许它转换回类类型。。。但是它只返回了一个引用成员,而放弃了其余的
作用域
,根据作用域用途的定义,这意味着它消失了,并在过程中破坏了类的内存。因此,您只剩下一个对已销毁对象的引用,这就是他们警告的bug