4

我将这个问题浓缩为一个小的代表性样本:

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());
}

我把那个代码放在test.d.

$ gdmd test.d
test.d:13: Error: cannot implicitly convert expression (this.foo) of type const(Foo) to test.Foo

我知道它告诉我用 转换返回值cast(test.Foo)foo,但是为什么呢?为什么它将成员解释为类型const(Foo),为什么需要我抛弃它const?我觉得我在这里做错了什么。

4

3 回答 3

5
const Foo getFoo()

是相同的

Foo getFoo() const

它使不可见的this参数const。因为const在 D 中是可传递的,这意味着当您尝试从 中返回一个成员变量时this,它const也会如此。如果foo是一个值类型,那么它只会复制它,然后返回一个可变的Foo不会有问题,因为它不会影响原来的。ButFoo是一个类,因此是一个引用类型。因此,返回是返回对所持有的foo完全相同的对象的引用。State没有复制。所以它必须const- 否则你会违反this参数的常量。

,抛弃const不是一个好的解决方案。正如在这个问题中所讨论的,丢弃然后改变值在 D 中实际上是非法的。当你这样做时,你违反了类型系统。编译器会让你这样做,但如果你在这样做时将自己的生命掌握在自己手中。如果底层对象实际上是 ,则尤其糟糕,因为在这种情况下您可能会遇到段错误。只有在万不得已的情况下,你才会抛弃它,除非你真的知道自己在做什么,否则你永远不会改变它。constimmutableconst

不,正确的解决方案是使返回类型const

const(Foo) getFoo() const

现在,您可以返回foo并使用它。如果你想要一个可变的Foo,那么你要么没有,要么你必须getFoo返回一个. 例如constgetFoofoo

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;
}

你要从这里带走的重要一点是constin D 是传递的。正如沃尔特·布莱特(Walter Bright)所说,“从头到尾都是乌龟。” 一旦某件事是const,它的所有部分都是const,除非你真的知道你在做什么,否则不要抛弃const它来绕过它。因此,如果要返回引用函数的成员变量的引用类型,则需要创建返回类型或创建它的副本并将其返回。constconst

于 2012-04-29T01:24:23.183 回答
4

我怀疑你真正想要的是:

class State
{
    private Foo foo;

    // When `this` is const, return const(Foo).
    // When `this` is immutable, return immutable(Foo).
    // When `this` is mutable, return Foo.
    inout(Foo) getFoo() inout
    {
        return foo;
    }
}

这相当于:

class State
{
    private Foo foo;

    Foo getFoo()
    {
        return foo;
    }

    const(Foo) getFoo() const
    {
        // `this.foo` is of type const(Foo), as const is transitive.
        return foo;
    }

    immutable(Foo) getFoo() immutable
    {
        // `this.foo` is of type immutable(Foo), as immutable is transitive.
        return foo;
    }
}
于 2012-04-29T02:10:55.010 回答
3

它将成员解释为const(Foo)因为您的方法签名是const Foo getFoo(),这意味着foo不会是可变的。

删除const它应该没问题。

于 2012-04-28T15:22:35.007 回答