我的 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
不可变,则构造函数将无法编译Error: cannot modify struct this Foo with immutable members
为什么会这样?我的印象是类或结构的不可变成员在构造函数结束之前不会变得不可变。
最佳答案
好的。一般来说,我建议不要使用带有 immutable
成员的结构。有太多的地方可以分配给一个是有用的。您通常希望对 struct 执行的操作是使其整体上可以是可变的、 const
或 immutable
。在大多数情况下,这只是有效。例如
struct Foo
{
int i;
this(int j) { i = j; }
this(Foo rhs) { this = rhs; }
}
void main()
{
immutable f = Foo(5);
}
编译就好了。通常会导致问题的一个方面是当你必须有一个 postblit 构造函数时,因为它们目前不适用于
const
或 immutable
结构(这是非常需要修复的东西,但由于如何,它仍然是一个悬而未决的问题类型系统有效——它可能导致我们不得不向语言添加复制构造函数,或者我们可能想出如何去做,但现在,它不起作用,而且可能很烦人)。但这只会在您需要 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
s,即 immutable
,这通常不是您想要的(尽管有时是)。因此,解决问题的第二种方法是将第一个解决方案更进一步并重载构造函数。例如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
通过分配给全局或静态变量来保证没有任何东西逃脱,并且构造函数的参数也不允许任何东西逃脱),并且因为它知道没有对 Foo
或其成员的引用可以逃避构造函数,它知道没有对此 Foo
的其他引用,因此它可以安全地将其转换为可变的、 const
或 immutable
而不违反类型系统。当然,这只有在您可以创建构造函数 pure
并且没有任何东西可以通过构造函数的参数逃脱时才有效,但通常情况就是这样,如果不是,您总是可以在可变性上重载构造函数,因为这不太可取.如果您真的想要
const
或 immutable
成员,则可以在结构上使用相同的技术,但同样,我建议不要这样做。它只会给你带来比它所值得的更多的麻烦,特别是当在声明变量时只制作整个结构 const
或 immutable
通常是微不足道的。
关于constructor - D 构造函数中的不变性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24234151/