切片
切片和数组看起来上很像,在实际使用时,你可能会想要使用切片,因为它相对数组来说,要更加灵活!
你可以对数组、切片、数组指针进行切片操作!
接下来我们演示切片的使用方式:
zig
var array = [_]i32{ 1, 2, 3, 4 };
const len: usize = 3;
const slice: []i32 = array[0..len];
for (slice, 0..) |ele, index| {
print("第{}个元素为:{}\n", .{ index + 1, ele });
}
print("slice 类型为{}\n", .{@TypeOf(slice)});
const slice_2: []i32 = array[0..array.len];
print("slice_2 类型为{}\n", .{@TypeOf(slice_2)});
zig
const print = @import("std").debug.print;
pub fn main() void {
var array = [_]i32{ 1, 2, 3, 4 };
const len: usize = 3;
const slice: []i32 = array[0..len];
for (slice, 0..) |ele, index| {
print("第{}个元素为:{}\n", .{ index + 1, ele });
}
print("slice 类型为{}\n", .{@TypeOf(slice)});
const slice_2: []i32 = array[0..array.len];
print("slice_2 类型为{}\n", .{@TypeOf(slice_2)});
}
打印结果如下:
sh
第1个元素为:1
第2个元素为:2
第3个元素为:3
slice 类型为[]i32
slice_2 类型为[]i32
切片的使用方式就是类似数组,不过[]
中的是索引的边界值,遵循“左闭右开”规则。
以上我们对数组取切片,左边界值为0,右边界值为 len
变量。
注意,这里说的是边界值有一个是变量(运行时可知),如果两个边界值均是编译期可知的话,编译器会直接将切片优化为数组指针。
🅿️ 提示
切片的本质:它本质是一个胖指针,包含了一个 指针类型 [*]T
和 长度。
同时,它的指针 slice.ptr
和长度 slice.len
均是可以操作的,但在实践中,请不要操作它们,这容易破坏切片的内部结构(除非你有把握每次都能正确的处理它们)。
切片指针
切片本身除了具有 len
属性外,还具有 ptr
属性,这意味着我们可以通过语法 slice.ptr
来操作切片的指针,它是一个多项指针!
当我们对切片元素取地址(&
)时,得到的是单项指针。
同时,切片本身还有边界检查,但是对切片指针做操作则不会有边界检查!
zig
var array = [_]i32{ 1, 2, 3, 4 };
// 边界使用变量,保证切片不会被优化为数组指针
var len: usize = 3;
_ = &len;
var slice = array[0..len];
print("slice 类型为{}\n", .{@TypeOf(slice)});
print("slice.ptr 类型为{}\n", .{@TypeOf(slice.ptr)});
print("slice 的索引 0 取地址,得到指针类型为{}\n", .{@TypeOf(&slice[0])});
zig
const print = @import("std").debug.print;
pub fn main() void {
var array = [_]i32{ 1, 2, 3, 4 };
// 边界使用变量,保证切片不会被优化为数组指针
var len: usize = 3;
_ = &len;
var slice = array[0..len];
print("slice 类型为{}\n", .{@TypeOf(slice)});
print("slice.ptr 类型为{}\n", .{@TypeOf(slice.ptr)});
print("slice 的索引 0 取地址,得到指针类型为{}\n", .{@TypeOf(&slice[0])});
}
打印结果如下:
sh
slice 类型为[]i32
slice.ptr 类型为[*]i32
slice 的索引 0 取地址,得到指针类型为*i32
哨兵切片
语法 [:x]T
是一个切片,它具有运行时已知的长度,并且还保证由该长度索引的元素的标记值。该类型不保证在此之前不存在哨兵元素,哨兵终止的切片允许元素访问 len 索引。
哨兵切片也可以使用切片语法 data[start..end :x]
的变体来创建,其中 data 是多项指针、数组或切片,x 是哨兵值。
哨兵切片认定哨兵位置处的元素是哨兵值,如果不是这种情况,则会触发安全保护中的未定义问题。
zig
// 显式声明切片类型
const str_slice: [:0]const u8 = "hello";
print("str_slice类型:{}\n", .{@TypeOf(str_slice)});
var array = [_]u8{ 3, 2, 1, 0, 3, 2, 1, 0 };
const runtime_length: usize = 3;
const slice: [:0]u8 = array[0..runtime_length :0];
print("slice类型:{}\n", .{@TypeOf(slice)});
zig
const print = @import("std").debug.print;
pub fn main() void {
// 显式声明切片类型
const str_slice: [:0]const u8 = "hello";
print("str_slice类型:{}\n", .{@TypeOf(str_slice)});
var array = [_]u8{ 3, 2, 1, 0, 3, 2, 1, 0 };
const runtime_length: usize = 3;
const slice: [:0]u8 = array[0..runtime_length :0];
print("slice类型:{}\n", .{@TypeOf(slice)});
}
打印结果如下:
sh
str_slice类型:[:0]const u8
slice类型:[:0]u8