我把这个问题浓缩成了一个小代表性样本:
import std.stdio;
class Foo
{
private int f;
}
class State
{
private Foo foo;
const Foo getFoo()
{
return foo; // This line here.
}
}
void main()
{
auto s = new State;
writeln(s.getFoo());
}
Run Code Online (Sandbox Code Playgroud)
我把那些代码放进去了test.d
.
$ gdmd test.d
test.d:13: Error: cannot implicitly convert expression (this.foo) of type const(Foo) to test.Foo
Run Code Online (Sandbox Code Playgroud)
我知道它告诉我要使用返回值cast(test.Foo)foo
,但为什么呢?为什么它会将成员解释为类型const(Foo)
,为什么需要我抛弃它const
?我觉得我在这里做了一些可怕的错事.
const Foo getFoo()
Run Code Online (Sandbox Code Playgroud)
是相同的
Foo getFoo() const
Run Code Online (Sandbox Code Playgroud)
它使隐形this
参数const
.因为const
在D中是传递的,这意味着当你尝试从中返回一个成员变量时this
,它也会const
是这样.如果foo
是值类型,那么它只是复制它,然后返回一个mutable Foo
不会有问题,因为它不会影响原始.但是Foo
是一个类,因此是一个引用类型.因此,返回foo
返回对完全相同的对象的引用State
.没有复制.所以它必须是const
-否则你会被违反的常量性this
参数.
不,虚掷const
是不是一个很好的解决方案.正如在这个问题中讨论的那样,const
在D中抛弃然后改变该值实际上是非法的.当你这样做时,你违反了类型系统.编译器会让你这样做,但是当你这样做时,你会把自己的生命掌握在自己手中.如果底层对象实际上是特别糟糕的immutable
,因为在这种情况下您可以获得段错误.const
如果你绝对必须,你只会抛弃它,除非你真的知道你在做什么,否则你永远不会改变它.
不,正确的解决方案是制作返回类型const
:
const(Foo) getFoo() const
Run Code Online (Sandbox Code Playgroud)
现在,您可以返回foo
并使用它.如果你想要一个可变的Foo
,那么你要么必须没有getFoo
成为const
,或者你必须有getFoo
回报的副本foo
.例如
Foo getFoo() const
{
//This would be cleaner if you provided a clone/dup function
//of some kind on Foo.
auto retval = new Foo;
retval.f = foo.f;
return retval;
}
Run Code Online (Sandbox Code Playgroud)
你从这里带走的重要一点是const
D在传递中.正如沃尔特·布莱特(Walter Bright)所说的那样,"它一直都是乌龟." 一旦有什么东西const
,它的所有部分都是const
,并且不会被抛弃去除const
它,除非你真的知道你在做什么.因此,如果要返回引用const
函数的成员变量的引用类型,则需要const
创建返回类型或创建它的副本并返回该类型.