如何在不破坏常量的情况下 return 不可变引用类型?
How can I return imutable reference types without break constness?
我在D:
中有如下代码
import std.stdio;
import std.container.array;
class RefType { }
class MyContainer {
private Array!RefType test;
RefType result() const { // I want const on this, not on return type
return test[0]; // use opIndex() from Array(T)
// Error: cannot implicitly convert expression (this.test.opIndex(0u))
// of type const(RefType) to main.RefType
}
}
int main(string[] argv) {
auto c = new MyContainer; auto r = c.result(); return 0;
}
如您所见,我想 return 来自自定义容器 class 的引用类型。但是 Array 的 opIndex() 没有给出这样做的权限,为什么?
我认为 opIndex()
应该 return 一个 RefType
而不是 const(RefType)
值,因为数组是 Array!RefType
.
这是一个错误吗?还是设计意图?如果这是有意的设计,我怎样才能得到我想要的?
I think that opIndex() should return a RefType instead of a
const(RefType) value because the Array is Array!RefType.
不,这是错误的。当您将 memthod 定义为 const
时,您还指定了 class 的所有成员也是常量。这意味着,无论成员在定义中的类型是什么,在您的 result
方法中它们(至少)是 const
。因此,编译器完全有理由返回它正在返回的错误。
通常(例如 C++
)解决这个问题的方法是定义两个(或者,在 D 中,三个)重载:
RefType result() {
return test[0];
}
RefType result() const {
return test[0];
}
RefType result() immutable {
return test[0];
}
所以,对于 class 是可变的情况,returns 是一个可变引用。一种情况是 class 是 const,returns 是一个 const 引用,另一种情况是 class 是不可变的,returns 是一个不可变引用。
然而,您会注意到,除了方法装饰之外,这三个实现完全相同。为了防止您定义三个相同的实现,D
具有 inout
修饰符:
RefType result() inout {
return test[0];
}
这个单一的定义取代了上面的所有三个定义。根据经验,只需像往常一样编写您的定义,但将 inout
放置在您原本要放置 const
.
的任何位置
I think that opIndex() should return a RefType instead of a
const(RefType) value because the Array is Array!RefType.
这个假设是错误的。由于您的 opIndex 方法被标记为常量。隐式给出的 this reference 也是 const
(is(this == const(MyContainer))。这意味着您通过它访问的所有内容也是 const,因为 D 的 const 是可传递的。当您在 const 方法中访问某些 const 时,您将得到一些 const。返回一些非 const来自此方法的方法在 D 中是非法的(幸运的是)。唯一可以从 const 方法返回的非 const 是没有间接寻址的值类型。
使您可以将类型作为非常量、常量和不可变类型工作的有效方法,您可以这样写:
inout(RefType) result() inout { ... }
我在D:
中有如下代码import std.stdio;
import std.container.array;
class RefType { }
class MyContainer {
private Array!RefType test;
RefType result() const { // I want const on this, not on return type
return test[0]; // use opIndex() from Array(T)
// Error: cannot implicitly convert expression (this.test.opIndex(0u))
// of type const(RefType) to main.RefType
}
}
int main(string[] argv) {
auto c = new MyContainer; auto r = c.result(); return 0;
}
如您所见,我想 return 来自自定义容器 class 的引用类型。但是 Array 的 opIndex() 没有给出这样做的权限,为什么?
我认为 opIndex()
应该 return 一个 RefType
而不是 const(RefType)
值,因为数组是 Array!RefType
.
这是一个错误吗?还是设计意图?如果这是有意的设计,我怎样才能得到我想要的?
I think that opIndex() should return a RefType instead of a const(RefType) value because the Array is Array!RefType.
不,这是错误的。当您将 memthod 定义为 const
时,您还指定了 class 的所有成员也是常量。这意味着,无论成员在定义中的类型是什么,在您的 result
方法中它们(至少)是 const
。因此,编译器完全有理由返回它正在返回的错误。
通常(例如 C++
)解决这个问题的方法是定义两个(或者,在 D 中,三个)重载:
RefType result() {
return test[0];
}
RefType result() const {
return test[0];
}
RefType result() immutable {
return test[0];
}
所以,对于 class 是可变的情况,returns 是一个可变引用。一种情况是 class 是 const,returns 是一个 const 引用,另一种情况是 class 是不可变的,returns 是一个不可变引用。
然而,您会注意到,除了方法装饰之外,这三个实现完全相同。为了防止您定义三个相同的实现,D
具有 inout
修饰符:
RefType result() inout {
return test[0];
}
这个单一的定义取代了上面的所有三个定义。根据经验,只需像往常一样编写您的定义,但将 inout
放置在您原本要放置 const
.
I think that opIndex() should return a RefType instead of a const(RefType) value because the Array is Array!RefType.
这个假设是错误的。由于您的 opIndex 方法被标记为常量。隐式给出的 this reference 也是 const (is(this == const(MyContainer))。这意味着您通过它访问的所有内容也是 const,因为 D 的 const 是可传递的。当您在 const 方法中访问某些 const 时,您将得到一些 const。返回一些非 const来自此方法的方法在 D 中是非法的(幸运的是)。唯一可以从 const 方法返回的非 const 是没有间接寻址的值类型。
使您可以将类型作为非常量、常量和不可变类型工作的有效方法,您可以这样写:
inout(RefType) result() inout { ... }