我目前正在实现一个基于二叉树的数据结构。作为其中的一部分,我有(目前是公开的,以便于测试)实例变量 left
和 right
作为每个 Node
的一部分用于创建我的结构的对象。我希望能够快速访问的一件事是一个 sub,它是使用这个函数完成的:
@property Node sub()
in {
assert(!isLeaf);
}
body {
return (val != left.val) ? left : right;
}
这里所指的所有东西都是公开的。现在,我尝试在合约中使用这个属性函数(特别是
out
block ,函数绑定(bind)到 result
的结果)。但是,当我这样做时,编译器提示我正在使用 const result
调用可变方法。目的。当我更改 sub
的签名时成为 @property const Node sub()
,但是,我得到了这个编译器错误:Error: cannot implicitly convert expression (this.val != this.left.val ? this.left : this.right) of type const(Node) to tournament2.Node
我在这里想念什么?我该如何解决这个问题?
最佳答案
最初的问题源于合约不能修改它们所属的对象的限制(否则,程序在调试和 Release模式下的行为可能会有所不同)。语言强制执行该限制的方式是使 this
指针 const
.
一个 const this
意思是你不能修改this
对象的字段,以及调用方法 - 这些方法本身必须注释为 const
,并且相同的限制适用于这些方法的代码。这解释了第一个错误:契约(Contract),即 const
,试图调用非 const
(可变)方法。由于允许修改可变方法this
,并且合约被禁止这样做,编译器禁止调用。
由于 D 的 constness 具有传递性,通过 this
访问的所有内容指针变为 const
.并且,如果任何类字段是引用类型,则它们的间接目标变为 const
也。这就是类型系统禁止修改任何可以通过 this
访问的内容的方式。指针。
这意味着如果 const
方法试图返回一个类字段(具有间接性,例如类类型 Node
),返回的类型也必须是 const
.这是第二条错误消息的来源:返回表达式试图转换 const Node
值,通过const this
获得, 到一个可变的 Node
.目前,语法 @property const Node sub()
表示方法本身是const
(并且具有 const this
),而不是返回类型。
现在,通常,在 C++ 中,具有适当 constness 支持的对象通常会对返回类字段的方法有多个重载:const
, 和非 const
. const
版本将返回 const
引用;非const
将返回一个非 const
引用。当我们可以访问可变对象时,需要这两个版本来获取可变字段引用,但仍然允许获取 const
。如果我们只有 const
,请引用访问对象。大多数时候,这两种方法的代码是相同的——只是函数签名不同。
这是 D 的 inout
在方法和它的一些参数或返回值上指定它意味着这些参数或返回值将具有与 this
相同的常量。 (被引用的对象)。这避免了返回 const
的简单情况下的代码重复。和可变值使用相同的代码。
我使用的语法是@property inout(Node) sub() inout
.我认为它可以用不止一种方式编写,但这种语法是明确的。在这里,inout(Node)
中的括号明确说明我们将属性应用于返回值,而不是函数,并放置方法(this
)inout
参数列表后的属性,如 const
在 C++ 中,明确指定它适用于函数本身。
关于properties - D:常量正确性——我做错了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21694152/