[Day-10]Zig:陣列(Array)和切片(Slices)

陣列 Array 是每個語言都有的基本功能,而切片 Slices 則是現代語言常見的陣列參照。

陣列

基本

陣列在編譯期確定長度、單一型別。宣告時可以省略長度,Zig 會根據初值自行推斷。

1
2
3
4
5
6
7
8
9
const std = @import("std");

pub fn main() void {
const arr1 = [_]u8{ 1, 2, 3, 4, 5 };
const arr2 = [5]u8{ 1, 2, 3, 4, 5 };
const arr3: [5]u8 = .{ 1, 2, 3, 4, 5 };

std.debug.print("{}, {}, {}\n", .{ arr1[0], arr2[0], arr3[0] });
}
1
1, 1, 1

長度

要得知陣列長度(元素數量),可以直接使用 array.len 欄位。

1
2
3
4
5
6
7
const std = @import("std");

pub fn main() void {
const arr = [_]u8{ 1, 2, 3, 4, 5 };
const length = arr.len;
std.debug.print("Length: {}", .{length});
}
1
Length: 5

賦值

如果是以 var 宣告的話,可以為元素重新賦值。

1
2
3
4
5
6
7
const std = @import("std");

pub fn main() void {
var arr = [_]u8{ 1, 2, 3, 4, 5 };
arr[1] = 100;
std.debug.print("{}", .{arr[1]});
}
1
100

邊界檢查

Zig 會進行邊界檢查,如果 Index 超出陣列範圍,引發編譯錯誤。

1
2
3
4
5
6
7
const std = @import("std");

pub fn main() void {
const arr = [_]u8{ 1, 2, 3, 4, 5 };
const val = arr[8]; // Error: Index outside!
std.debug.print("{}", .{val});
}
1
2
3
$ zig run outside.zig
outside.zig:5:21: error: index 8 outside array of length 5
const val = arr[8]; // Error: Index outside!

切片

基本

切片是對於一個陣列的指標和長度資訊。它是一個陣列的一部分,由於是指標,不實際儲存陣列數值,適合傳遞。切片也可以透過 slice.len 取代長度。

它的語法是 array[n..m],其中 n 是開始索引,m 是結束索引(不包含)。所以 array[0..3] 就是取第 0~2。如果要取到最後的話,m 可以省略,也就是 array[n..]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const std = @import("std");

pub fn main() void {
const array = [_]u8{ 1, 2, 3, 4, 5 };
const slice1 = array[0..2]; // {1, 2}
const slice2 = array[0..4]; // {1, 2, 3}

std.debug.print("Slice 1:\n", .{});
std.debug.print(" {}, {}\n", .{ slice1[0], slice1[1] });
std.debug.print(" Length: {}\n\n", .{slice1.len});

std.debug.print("Slice 2:\n", .{});
std.debug.print(" Length: {}", .{slice2.len});
}
1
2
3
4
5
6
Slice 1:
1, 2
Length: 2

Slice 2:
Length: 4

型別

1
2
3
4
5
6
7
8
9
10
const std = @import("std");

pub fn main() void {
const array = [_]u8{ 1, 2, 3, 4, 5 };
const slice = array[0..];

std.debug.print("Array type: {}\n", .{@TypeOf(array)});
std.debug.print("Slice type: {} ", .{@TypeOf(slice)});
}

1
2
Array type: [5]u8
Slice type: *const [5]u8

傳遞

因為切片只是指標,所以很適合傳遞,而且它帶有長度資訊,所以可以不必另外傳遞長度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const std = @import("std");

pub fn main() void {
const array1 = [_]u8{ 1, 2, 3, 4, 5 };
do_something(&array1);

const array2 = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
do_something(&array2);

do_something(array2[2..6]);
}

fn do_something(data: []const u8) void {
std.debug.print("Value: {}\n", .{data[0]});
std.debug.print("length: {}\n", .{data.len});
std.debug.print("Type: {}\n\n", .{@TypeOf(data)});
}
1
2
3
4
5
6
7
8
9
10
11
Value: 1
length: 5
Type: []const u8

Value: 1
length: 8
Type: []const u8

Value: 3
length: 4
Type: []const u8

字串

字串實際上是 u8 切片。

1
2
3
4
5
6
7
8
9
const std = @import("std");

pub fn main() void {
const arr = "Hello World";
const arr_type = @TypeOf(arr);
const length = arr.len;

std.debug.print("Type: {}, Length: {}\n", .{ arr_type, length });
}
1
Type: *const [11:0]u8, Length: 11

參考

本文以 Zig 0.13.0 為主。並同時發佈在:


留言可能不會立即顯示。若過了幾天仍未出現,請 Email 聯繫:)