[英]Immutability in D constructors
My previous question discussed making a copy constructor like so: 我之前的问题讨论过如下制作复制构造函数:
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);
}
But, if I make i
immutable, the constructor fails to compile with 但是,如果我使
i
不可变,构造函数无法编译
Error: cannot modify struct this Foo with immutable members
错误:无法使用不可变成员修改struct this Foo
Why is this the case? 为什么会这样? I was under the impression that immutable members of a class or struct do not become immutable until the end of the constructor is reached.
我的印象是,在到达构造函数的末尾之前,类或结构的不可变成员不会变为不可变。
Okay. 好的。 In general, I'd advise against having structs with
immutable
members. 一般来说,我建议不要使用
immutable
成员。 There are just too many places where it's useful to be able to assign to one. 有太多的地方可以分配给一个有用的地方。 What you typically want to do with a struct is make it so that it can be mutable,
const
, or immutable
as a whole. 你通常想要对结构做什么是使它成为一个整体可变,
const
或immutable
的。 And for the most part, that just works. 而在大多数情况下,这才有效。 eg
例如
struct Foo
{
int i;
this(int j) { i = j; }
this(Foo rhs) { this = rhs; }
}
void main()
{
immutable f = Foo(5);
}
compiles just fine. 编译得很好。 The one area that generally causes trouble with that is when you have to have a postblit constructor, because those don't currently work with
const
or immutable
structs (it's something that sorely needs to be fixed, but it's still an open problem due to how the type system works - it may result in us having to add copy constructors to the language, or we may figure out how to do it, but for now, it doesn't work, and it can be annoying). 通常会导致问题的一个方面是当你必须有一个postblit构造函数时,因为那些当前不使用
const
或immutable
结构(这是一个非常需要修复的东西,但它仍然是一个开放的问题,因为如何类型系统工作 - 它可能导致我们不得不在语言中添加复制构造函数,或者我们可能会弄清楚如何执行它,但是现在,它不起作用,并且它可能很烦人)。 But that only affects you if you need a postblit constructor, which most structs don't need (the problem will be fixed eventually though, because it really needs to be; it's just a question of how and when). 但是这只会影响你,如果你需要一个postblit构造函数,大多数结构不需要(问题最终会被修复,因为它确实需要;它只是一个如何和何时的问题)。
However, to answer your question more generally, let's look at a class. 但是,为了更广泛地回答你的问题,让我们来看一个班级。 For instance, this code won't compile, because the constructor is not
immutable
, and the compiler can't convert an immutable
class object to a mutable one (it can do that with structs, because it makes a copy, but with a class, it's just copying the reference, not the object, so it doesn't work): 例如,这段代码不会编译,因为构造函数不是
immutable
,并且编译器不能将immutable
类对象转换为可变类(它可以使用结构来实现,因为它创建了一个副本,但是有一个类,它只是复制引用,而不是对象,所以它不起作用):
class Foo
{
int i;
this(int j) { i = j; }
}
void main()
{
auto f = new immutable Foo(5);
}
Instead of that compiling, you get this lovely error message: 而不是编译,你得到这个可爱的错误信息:
q.d(10): Error: mutable method q.Foo.this is not callable using a immutable object
q.d(10): Error: no constructor for Foo
There are three ways to solve this. 有三种方法可以解决这个问题。 The first is to make the constructor
immutable
第一个是使构造函数
immutable
class Foo
{
int i;
this(int j) immutable { i = j; }
}
and that works, but it makes it so that you can only construct Foo
s which are immutable
, which usually isn't what you want (though it sometimes is). 这是有效的,但它使得你只能构造
immutable
Foo
,这通常不是你想要的(虽然它有时是)。 So, the second way to solve the problem would be to take the first solution a step further and overload the constructor. 因此,解决问题的第二种方法是将第一个解决方案更进一步,并使构造函数重载。 eg
例如
class Foo
{
int i;
this(int j) { i = j; }
this(int j) immutable { i = j; }
}
However, that requires code duplication, which isn't a lot here, but it could be a lot for other types. 但是,这需要代码重复,这在这里并不多,但对于其他类型可能会有很多。 So, what is generally the best solution is to make the constructor
pure
. 因此,通常最好的解决方案是使构造函数
pure
。
class Foo
{
int i;
this(int j) pure { i = j; }
}
This works, because the compiler then knows that nothing has escaped the constructor (since pure
guarantees that nothing escapes by being assigned to a global or static variable, and the constructor's parameters don't allow anything to escape either), and because it knows that no references to Foo
or its members can escape the constructor, it knows that there are no other references to this Foo
and that it therefore can safely convert it to mutable, const
, or immutable
without violating the type system. 这是有效的,因为编译器然后知道没有任何东西已经转义构造函数(因为
pure
保证通过分配给全局或静态变量没有任何转义,并且构造函数的参数也不允许任何东西转义),并且因为它知道没有对Foo
或其成员的引用可以转义构造函数,它知道没有其他对此Foo
引用,因此它可以安全地将其转换为mutable, const
或immutable
而不违反类型系统。 Of course, that only works if you can make the constructor pure
and nothing can escape via the constructor's arguments, but that's usually the case, and when it isn't, you can always just overload the constructor on mutability, much as that's less desirable. 当然,这只有在你可以使构造函数
pure
并且没有任何东西可以通过构造函数的参数进行转义时才有效,但通常就是这种情况,当它不存在时,你总是可以在可变性上重载构造函数,就像那样不太可取。 。
The same techniques can be used on structs if you really want const
or immutable
members, but again, I'd advise against it. 如果你真的想要
const
或immutable
成员,可以在结构上使用相同的技术,但同样,我建议反对它。 It's just going to cause you more trouble than it's worth, especially when it's usually trivial to just make the whole struct const
or immutable
when declaring a variable. 这只会给你带来更多的麻烦而不是它的价值,特别是在声明一个变量时,只需要使整个struct
const
或immutable
一般都是微不足道的。
Making members of structs immutable
stops assigning to the struct which in turn causes quite a few issues, you may which to rethink that. 使结构成员
immutable
停止分配给结构,这反过来会导致相当多的问题,你可能会重新考虑这一点。
Otherwise assign the members directly instead of relying on the assignment operator: 否则直接分配成员而不是依赖赋值运算符:
struct Foo {
immutable int i;
this(int j) { i = j; }
this(in Foo rhs) { this.i = rhs.i; }
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.