Properties D:常量正确性-我做错了什么?

Properties D:常量正确性-我做错了什么?,properties,constants,d,Properties,Constants,D,我目前正在实现一个基于二叉树的数据结构。作为其中的一部分,我有(为了便于测试,目前是公共的)实例变量left和right作为创建结构时使用的每个节点对象的一部分。我希望能够快速访问sub,这是使用以下功能完成的: @property Node sub() in { assert(!isLeaf); } body { return (val != left.val) ? left : right; } 这里提到的所有东西都是公开的

我目前正在实现一个基于二叉树的数据结构。作为其中的一部分,我有(为了便于测试,目前是公共的)实例变量
left
right
作为创建结构时使用的每个
节点
对象的一部分。我希望能够快速访问sub,这是使用以下功能完成的:

@property Node sub() 
    in {
        assert(!isLeaf);
    }
    body {
        return (val != left.val) ? left : right;
    }
这里提到的所有东西都是公开的。现在,我尝试在契约中使用这个属性函数(特别是
out
块,函数的结果绑定到
result
)。然而,当我这样做时,编译器抱怨我正在使用const
result
对象调用一个可变方法。但是,当我将
sub
的签名更改为
@property const Node sub()
时,却出现了以下编译器错误:

错误:无法将const(Node)类型的表达式(this.val!=this.left.val?this.left:this.right)隐式转换为tournament2.Node


我错过了什么?如何解决此问题?

最初的问题源于契约无法修改其所属对象的限制(否则,程序在调试和发布模式下的行为可能会有所不同)。语言强制执行该限制的方式是使
this
指针
const

const this
意味着您不能修改
this
对象的字段,至于调用方法,这些方法本身必须注释为
const
,这些方法的代码也受到同样的限制。这解释了第一个错误:合约是
const
,试图调用非
const
(可变)方法。由于允许可变方法修改
,并且禁止契约这样做,因此编译器禁止调用

由于D的常量的可传递性,通过
这个
指针访问的所有内容都变成
常量
。而且,如果任何类字段都是引用类型,那么它们的间接目标也将成为
const
。这就是类型系统将禁止修改通过
This
指针可以访问的任何内容的方式

这意味着,如果
const
方法试图返回一个类字段(带有间接项,例如
节点
之类的类类型),则返回的类型也必须是
const
。这是第二条错误消息的来源:返回表达式试图将通过
常量This
获得的
常量节点
值转换为可变的
节点
。目前,语法
@property const Node sub()
表示方法本身是
const
(并且具有as
const this
),而不是返回类型

现在,一般来说,C++中,一个具有适当的常态性支持的对象通常会有多个重载,返回类字段的方法:<代码> const ,以及非->代码> const 。

const
版本将返回
const
引用;非
常量
将返回非
常量
引用。当我们有权访问可变对象时,需要这两个版本来允许获取可变字段引用,但如果我们只有对对象的
const
访问权,则仍然允许获取
const
引用。大多数情况下,这两个方法的代码是相同的——只有函数签名不同

这就是D的
inout
的作用。在方法及其某些参数或返回值上指定它意味着这些参数或返回值将具有与
this
(所引用的对象)相同的常量。对于返回的
const
和可变值使用相同代码的简单情况,这避免了代码重复


我使用的语法是
@property inout(Node)sub()inout
。我认为它可以用多种方式编写,但这种语法是明确的。这里,在<代码> IONT(NoCub)< /C>中的父母们明确地指出,我们在返回值上应用属性,而不是在函数上应用方法,并且在参数列表之后放置方法(<代码> < <代码> > <代码> IUDUMENT/COD>属性,如C++中的代码> const < /Cord>。明确指定它应用于函数本身。

尝试将签名更改为
@property inout(Node)sub()inout
@CyberShadow:这就解决了问题,谢谢!你能给我描述一下为什么会这样吗?我想了解问题的根源,这样我以后就不会被这个问题绊倒了。