d中不变与数组
原文
rumbu:想理解编译器行为:
struct SimpleStruct { int x;}
struct ComplexStruct { int[] x; }
void main()
{
SimpleStruct[] buf1;
immutable(SimpleStruct)[] ibuf1;
buf1[0 .. 10] = ibuf1[0 .. 10];
//工作
ComplexStruct[] buf2;
immutable(ComplexStruct)[] ibuf2;
buf2[0 .. 10] = ibuf2[0 .. 10];
//错误,不能隐式转换`immutable(ComplexStruct)[]`类型的`ibuf2[0..10]`到`ComplexStruct[]`
}
WebFreak001:
规范说:
无可变间接引用值(包括不含具可变间接引用字段的构)可在mutable,const,immutable,const shared,inout和inout shared间隐式转换.
因此第一个结构可在可变/不变/常间隐式转换,因为它不包含(可变数组/指针/引用)的可变间接.
Stanislav Blinov:因为is(typeof(immutable(ComplexStruct).x)==immutable(int[])).不能绑定不变数组到可变数组.需要深复制,即复制构造器.
Steven Schveighoffer:
第一例,有个包含整数的简单结构.复制该构时,无间接(指针),即允许调整可变性:
immutable s = SimpleStruct(5);
SimpleStruct s2 = s; // 好,复制所有
第二例,int[]包含指针.如果复制它,就不能改变类型的可变性,因为它有到不变数据的可变指针:
immutable s = ComplexStruct([5]);
ComplexStruct s2 = s; // 错误,不能隐式转换,有个`间接`.
为什么?假设允许它,s2是可变的,即s2.x是可变的.现在可这样:
s2.x[0] = 6;
突然之间,可修改不变数据了!这是禁止的,因而不能复制结构.
Stanislav Blinov:
不完全是.这里可能有个真正错误:
struct S
{
int[] x;
// 没用它,后复制也不行
this(ref return scope inout S other)
{
x = other.x.dup;
}
void opAssign(ref return scope inout S other)
{
x = other.x.dup;
}
}
void main()
{
immutable(S)[] src = [S([1, 2]), S([3, 4])];
auto dst = new S[src.length];
//dst[0 .. $] = src[0 .. $];
//即使定义了`opAssign`,也不编译
//这可以:
foreach (i, ref it; dst)
it = src[i];
}
规范:
根据规范,(在检查重叠后),分配切片应与foreach循环一样.但没有,只是尝试隐式转换,但失败了.
现在,因为有了复制构造器,切片赋值应该尝试复制赋值元素(即无opAssign时,先试复制构造器).
Steven Schveighoffer:
我同意在此切片赋值同复制构造器应工作.我认为目前是它仍依赖memcpy+后复制,(数组运行时多数还是神奇函数).
后复制不管用,因为它先按原样复制数据,即仍然是不变的,只有在后复制之后才是可变的.
注意,这不是构造,它应该用opAssign.再说一遍,可能是运行时用了memcpy+后复制.如果无报告,应该是这样.
简单证明这是漏洞:
immutable (ComplexStruct)[] arr;
ComplexStruct[] arr2;
arr2[0] = arr[0]; // ok
arr2[] = arr[]; // 错误
如果可复制元素,则应可复制所有元素.
浙公网安备 33010602011771号