我目前正在实现基于二叉树的数据结构。作为其中的一部分,我(实际上是公开的,为了更容易测试)实例变量left
和right
作为创建我的结构时使用的每个Node
对象的一部分。我希望能够快速访问的其中一个是sub,它是使用此函数完成的:
@property Node sub()
in {
assert(!isLeaf);
}
body {
return (val != left.val) ? left : right;
}
这指的所有内容都是公开的。现在,我尝试在契约中使用此属性函数(特别是out
块,其结果是函数绑定到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
我在这里缺少什么?我该如何解决这个问题?
答案 0 :(得分:8)
最初的问题源于合同无法修改其所属对象的限制(否则,程序在调试和发布模式下的行为可能会有所不同)。语言强制执行该限制的方式是使this
指针const
。
const this
表示您无法修改this
对象的字段,而对于调用方法,这些方法本身必须注释为const
,同样的限制适用于这些方法的代码。这解释了第一个错误:合约const
试图调用非const
(可变)方法。由于允许可变方法修改this
,并且禁止合同这样做,编译器禁止调用。
由于D& constness的传递性,通过this
指针访问的所有内容都变为const
。并且,如果任何类字段是引用类型,则它们的间接目标也变为const
。这就是类型系统将禁止修改可以通过this
指针访问的任何内容。
这意味着如果const
方法试图返回一个类字段(具有间接性,例如像Node
这样的类类型),则返回的类型也必须是{{1 }}。这是第二条错误消息的来源:返回表达式尝试将通过const
获得的const Node
值转换为可变const this
。目前,语法Node
表示方法本身为@property const Node sub()
(并且为const
),而不是返回类型。
现在,通常,在C ++中,具有适当const支持的对象通常会为返回类字段的方法提供多个重载:const this
和非 - const
。 const
版本将返回const
引用;非const
将返回非const
引用。当我们有权访问可变对象时,需要这两个版本才能获得可变字段引用,但如果我们只有const
访问该对象,则仍允许获取const
引用。大多数情况下,两种方法的代码是相同的 - 只有函数签名会有所不同。
这是D' const
的用武之地。在方法及其一些参数或返回值上指定它意味着这些参数或返回值将具有与{{1}相同的常量(被引用的对象)。这避免了返回inout
和可变值使用相同代码的简单情况下的代码重复。
我使用的语法是this
。我认为它可以用多种方式编写,但这种语法是明确的。这里,const
中的parens明确表示我们在返回值而不是函数上应用属性,并将方法(@property inout(Node) sub() inout
)inout(Node)
属性放在参数列表之后,与C ++中的this
一样,明确指出它适用于函数本身。