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];//闰年2月加1天
writeln("非闰年: ", monthDays);
writeln("闰年: ", 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("1切片开始为: ", slice1);
writeln("2切片开始为: ", slice2);
writeln("3切片开始为: ", slice3);
slice2[0] = 42;//钥匙也可以改值
slice3[0] = 43;//另一个实体
writeln("1切片后为: ", slice1);
writeln("2切片后为: ", slice2);
writeln("3切片后为: ", 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]]
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现