d的数组问题
原文
改变结构位置会怎样?所以在main()时,X结构一定在栈中,而下面的一定在堆中,是吧?
import std;
//void main() {
struct X
{
struct Y {
int i = 10;
alias i this;
}
Y[] y = [Y.init];//.1
string toString() {
return y.format!"%s";
}
}
void main() {
X[2] x;//.2
x.writeln; // [[10], [10]]
x[0].y[0] = 0; // [[0], [0]]
x.writeln;
x[0].y.length++;
x[0].y[1] = 1;
x[1].y[0] = 2;
x.writeln; // [[0, 1], [2]]
} /* 输出其他状态
[[10], [10]]
[[0], [0]]
[[2, 1], [2]]
*/
.1这里,
Y[] y = [Y.init];
按内存切片声明y(可是栈或堆),并把它初化为包含Y.init的1元素数组.
这是D中的重要怪癖:每当用字面初化聚集数组成员时,聚集的所有实例都*相同*底层数组.
如果想避免,建议在构造器中初化y.然后会更明确过程.
.2,
X[2] x;
这里声明了包含2个X元素的静态数组,每个X实例都包含[Y.init]数组切片的y成员.每个X实例都在栈上;但是,它们的y成员在其他地方,这里为[Y.init]数组.
重要:如上,这里x[0].y和x[1].y,这两个不同切片都引用[Y.init]该相同数组.
栈 全局数据
x[0] {
Y[] y; -----+----> [ Y.init ]
} |
x[1] { |
Y[] y; -----'
}
这里
x.writeln; // [[10], [10]]
x[0].y[0] = 0; // [[0], [0]]
这行是说,在x数组的第一个元素中,把0赋值给y切片数组中的第一个元素.由于x[0].y和x[1].y都指向同一底层数组,因此x[0].y修改它会使x[1].y也修改了.
栈 全局数组
x[0] {
Y[] y; -----+----> [ 0 ]
} |
x[1] { |
Y[] y; -----'
}
因此x[0].y[0]==0及x[1].y[0]==0.因为x[0].y.ptr==x[1].y.ptr.
这里:
x.writeln;
x[0].y.length++;
此行增加x[0].y数组长度.由于在程序全局数据区域分配的,并按1元素字面声明它,因此没有扩展空间.
此时,为了兑现延长数组请求,druntime会在堆上分配新数组,并复制旧数组,然后扩大长度为2.现在:
栈 全局数据 堆
x[0] {
Y[] y; ----------------> [ 0, 0 ]
}
x[1] {
Y[] y; ----> [ 0 ]
}
关键点:x[0].y和x[1].y现在指向两个位于不同位置的不同数组.A中变化不再反映在B中.
上面显示的[0]数组,原来是x[0].y数组,但不再这样,因为druntime已在堆中复制了它,并更新了x[0].y以指向副本而不是源.但是,x[1].y继续指向原数组.
x[0].y[1] = 1;
变成:
栈 全局 堆
x[0] {
Y[] y; -------------> [ 0, 1 ]
}
x[1] {
Y[] y; -----> [ 0 ]
}
这里,
x[1].y[0] = 2;
为:
栈 全局 堆
x[0] {
Y[] y; -------------> [ 0, 1 ]
}
x[1] {
Y[] y; -----> [ 2 ]
}
而
x.writeln;// [[0, 1], [2]]
显示了上面.
如果把X置为"静态构",会看到相同输出.
import std;
void main() {
//static
struct X
{
static struct Y {
//...
}}
static struct Bar {
string s;
string toString() {
return s;
}
}
auto list = "sixtwoone".chunks(3);
list.map!(c => c.to!string)
.map!Bar.array.writeln; // [six, two, one]
//...
}
浙公网安备 33010602011771号