天天看點

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]]      
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]
   //...
}