05用d编程切片

切片,动态数组的别名.
[起…尾]是这样的[..),即左包右不包
切片不是实体,就像钥匙一样.
如果切片修改实体,则实体也跟着变了.
[a…a],大小为0,[a… ] , ],` 表示数组长度,等价于数组.长度..dup`复制实体.
如下:

import std.stdio;

void main() {
    int[12] monthDays =
        [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];

    int[] leapYear = monthDays.dup;

    ++leapYear[1];   // increments the days in February

    writeln("Non-leap year: ", monthDays);
    writeln("Leap year    : ", leapYear);
}

赋值:

    int[3] a = [ 1, 1, 1 ];
    int[3] b = [ 2, 2, 2 ];

    a = b;        // a中都是2了,
    writeln(a);

静态数组的赋值必须长度一样.长度属于类型一部分,静态数组,赋值为实体.
静态数组都是实体.
赋值操作对切片完全不一样,赋值是生成切片.切片的赋值则是切片.除非.dup.idup.

 int[] odds = [ 1, 3, 5, 7, 9, 11 ];
    int[] evens = [ 2, 4, 6, 8, 10 ];

    int[] slice;//空的

    slice = odds[2 .. $ - 2];
    writeln(slice);

    slice = evens[1 .. $ - 1];
    writeln(slice);

相当于说动态数组有两种含义:1动态数组,2切片.
切片是间接的,类似于c++的串视,是一种视图.保存的是起始位置长度,而不是实体.修改实体,多个视图都会变化.

import std.stdio;

void main() {
    int[] slice = [ 1, 3, 5, 7, 9, 11, 13, 15 ];
    int[] half = slice[0 .. $ / 2];
    int[] quarter = slice[0 .. $ / 4];

    quarter[1] = 0;     //切片修改实体

    writeln(quarter);
    writeln(half);
    writeln(slice);//都变了
}

添加时,一旦没有容纳新元素的空间,则自动生成新实体,就单独变化了.相当于写时复制.

 quarter ~= 42;    //切片离开共享
 quarter[1] = 0;   //再修改,已经分家了,影响不了了

显示增加切片的长度,也会生成新实体.

++quarter.length;
//或
quarter.length += 5; 

各种方式缩短切片,则不会生成新的.
capacity,则强制规定切片大小,类似静态数组长度.只要数组元素个数达到此,然后再增加时,就会生成新实体,为0时表明这不是最长的原始切片(实体),对这个切片添加新元素,导致重新生成新实体.
即用0与非0来区分是钥匙还是实体.0则为钥匙.为切片.非0则,本切片为实体.

 if (slice.capacity == 0) {
    //如对本切片加元素,则生成新实体
        // ...
    } else {//剩余可对切片加的个数
        auto 剩余空间= slice.capacity - slice.length;
        // ...
    }

特例是最开始几个切片可能有相同大小容量,一旦改了一个后,其余的切片都变成钥匙,都为0了,因为你不是实体,那个改了的切片才是实体.你钥匙再变化一下,你就变成了新的实体.
为切片预留空间//附加元素成本很高:

import std.stdio;

void main() {
    int[] slice;

    slice.reserve(20);
    writeln(slice.capacity);//31

    foreach (element; 0 .. 17) {
        slice ~= element;  //不会移动
    }//超过31
}

对所有元素操作,对数组(静态/(动态/切片))都适用

import std.stdio;

void main(){
     double [3] a = [10,20,30];
    double [3] b = [2,3,4];

    double [3] 结果 = a [] + b [] ;
    writeln(结果);
}

操作符可为:
算术操作+, -, 星号, /, %, 和 ^^;
二元操作符^, &, 和 |;
一元操作符-,~
赋值也可以:=, +=, -=, 星号=, /=, %=, ^^=, ^=, &=, 和 |=.
这项特征,不仅用于两项数组,还可与数组匹配的表达式连用.

    double[3] a = [ 10, 20, 30 ];
    a[] /= 4;

    writeln(a);
//及
    a[] = 42;//这是[]=操作符,每个元素都是42
    writeln(a);

小心区别:

 slice2 = slice1;//传递的是钥匙
 slice3[] = slice1;//[]=是操作符,两边都是切片,一个个的赋值将1切片的值挨个的赋值给3切片.都是实体.

再看一个,仔细观察:

import std.stdio;

void main() {
    double[] slice1 = [ 1, 1, 1 ];
    double[] slice2 = [ 2, 2, 2 ];
    double[] slice3 = [ 3, 3, 3 ];

    slice2 = slice1;//slice2是钥匙,1与2是一样的
    slice3[]=slice1;//[]=是操作符,挨个赋值给3切片
    //2切片是钥匙.1与3切片是实体
    writeln("slice1 开始为: ", slice1);
    writeln("slice2 开始为: ", slice2);
    writeln("slice3 开始为: ", slice3);

    slice2[0] = 42;//钥匙也可以改值
    slice3[0] = 43;//另一个实体
    writeln("slice1 后面为: ", slice1);
    writeln("slice2 后面为: ", slice2);
    writeln("slice3 后面为: ", slice3);
}

危险是:改变值后才注意到可能的区别,即有两种切片.一种是钥匙,一种是实体.
多维数组:

  /* ... */ array = [
                      [ 10, 11, 12 ],
                      [ 20, 21, 22 ],
                      [ 30, 31, 32 ],
                      [ 40, 41, 42 ]
                    ];
 array ~= [ 50, 51 ]; //加元素
    array[0] ~= 13;   //加元素  
//[[10, 11, 12, 13], [20, 21, 22], [30, 31, 32], [40, 41, 42], [50, 51]]
//固定数组
int[2][3][4] array;

创建切片的切片.

import std.stdio;

void main() {
    int[][] s = new int[][](2, 3);
    writeln(s);//[[0, 0, 0], [0, 0, 0]]
}
发布了376 篇原创文章 · 获赞 25 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/fqbqrr/article/details/104587107