D构造函数的不变性

时间:2014-06-15 21:11:52

标签: constructor d immutability copy-constructor

我的previous question讨论了如此制作复制构造函数:

struct Foo {
    int i;

    this(int j) { i = j; }

    this(Foo rhs) { this = rhs; }
}

void main()
{
    auto f = Foo(5);
    auto g = new Foo(f);
}

但是,如果我使i不可变,则构造函数无法使用

进行编译
  

错误:无法使用不可变成员修改struct this Foo

为什么会这样?我的印象是,在到达构造函数的末尾之前,类或结构的不可变成员不会变为不可变。

2 个答案:

答案 0 :(得分:9)

好。一般来说,我建议不要与immutable成员结成。有太多的地方可以分配给一个有用的地方。您通常想要对结构执行的操作是使它可以变为可变,constimmutable作为整体。而在大多数情况下,这才有效。 e.g。

struct Foo
{
    int i;

    this(int j) { i = j; }

    this(Foo rhs) { this = rhs; }
}

void main()
{
    immutable f = Foo(5);
}

编译得很好。通常会导致问题的一个方面是当你必须有一个postblit构造函数时,因为那些目前不使用constimmutable结构(它是一个非常痛苦的东西)需要修复,但由于类型系统的工作方式,它仍然是一个开放的问题 - 它可能导致我们不得不在语言中添加复制构造函数,或者我们可能会弄清楚如何执行它,但是现在,它不起作用,它可能很烦人)。但这只会影响你,如果你需要一个postblit构造函数,大多数结构不需要(问题最终会被解决,因为它确实需要;它只是一个如何和何时的问题)

然而,为了更一般地回答你的问题,让我们来看一个班级。例如,这段代码不会编译,因为构造函数不是immutable,并且编译器无法将immutable类对象转换为可变对象(它可以通过结构,因为它是一个副本,但是对于一个类,它只是复制引用,而不是对象,所以它不起作用):

class Foo
{
    int i;

    this(int j) { i = j; }
}

void main()
{
    auto f = new immutable Foo(5);
}

而不是编译,你得到这个可爱的错误信息:

q.d(10): Error: mutable method q.Foo.this is not callable using a immutable object
q.d(10): Error: no constructor for Foo

有三种方法可以解决这个问题。第一个是构造函数immutable

class Foo
{
    int i;

    this(int j) immutable { i = j; }
}

这是有效的,但它使得你只能 构建Foo immutable,这通常不是你想要的(虽然它有时是)。因此,解决问题的第二种方法是将第一个解决方案更进一步,并使构造函数重载。 e.g。

class Foo
{
    int i;

    this(int j) { i = j; }

    this(int j) immutable { i = j; }
}

然而,这需要代码重复,这里不是很多,但对于其他类型可能会有很多。那么,最佳解决方案通常是构造函数pure

class Foo
{
    int i;

    this(int j) pure { i = j; }
}

这是有效的,因为编译器知道没有任何东西已经转义构造函数(因为pure通过分配给全局或静态变量来保证没有任何转义,并且构造函数的参数不会被转义。 t允许任何事情逃脱),并且因为它知道没有对Foo或其成员的引用可以逃避构造函数,它知道没有其他对此Foo的引用,因此它可以安全在不违反类型系统的情况下将其转换为mutable,constimmutable。当然,只有当可以制作构造函数pure并且没有任何东西可以通过构造函数的参数进行转义时才有效,但是 >这种情况,当它不是时,你总是可以在构造函数上重载可变性,就像那样不太可取。

如果您真的想要constimmutable成员,可以在结构上使用相同的技术,但我再次提出建议。这会给你带来更多的麻烦而不是它的价值,特别是当宣布一个变量时,只需要制作整个结构constimmutable通常是微不足道的。

答案 1 :(得分:2)

使结构immutable的成员停止分配给结构,这反过来会导致相当多的问题,你可以重新考虑它。

否则直接分配成员而不是依赖赋值运算符:

struct Foo {
    immutable int i;

    this(int j) { i = j; }

    this(in Foo rhs) { this.i = rhs.i; }
}