原文 改變
結構
位置會怎樣?是以在
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]]
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]
//...
}