在 Zig 语言中,数组(Array) 是一种固定大小的序列,而 切片(Slice) 是数组的动态视图,提供更灵活的操作方式。Zig 通过严格的类型系统确保数组和切片的安全性,并提供了强大的 指针、索引、迭代内存管理 机制。本文将详细介绍 Zig 中的数组和切片,并配以示例代码。


📖 目录

  1. 数组基础
  2. 数组的操作
  3. 多维数组
  4. 切片基础
  5. 切片操作
  6. 动态分配切片(std.ArrayList)
  7. 数组 vs. 切片
  8. 参考资料

1. 数组基础

Zig 数组的大小 在编译时固定,数组的元素类型必须一致。

🔹 数组的声明

const arr: [5]i32 = [5]i32{1, 2, 3, 4, 5};

  • [5]i32:表示数组包含 5 个 i32 类型的元素
  • {1, 2, 3, 4, 5}:数组的初始化值。

🔹 访问数组元素

const std = @import("std");

pub fn main() void {
    const arr: [3]i32 = [3]i32{10, 20, 30};
    
    std.debug.print("第一个元素: {}\n", .{arr[0]}); // 10
    std.debug.print("最后一个元素: {}\n", .{arr[2]}); // 30
}

注意:访问超出范围的索引会导致 编译错误运行时错误(如果开启安全检查)。


2. 数组的操作

🔹 遍历数组

pub fn main() void {
    const arr = [_]i32{5, 10, 15, 20};

    for (arr) |value| {
        std.debug.print("{}\n", .{value});
    }
}

  • _ 让 Zig 自动推断数组长度
  • for (arr) |value| {} 遍历数组。

🔹 获取数组长度

const arr = [_]i32{10, 20, 30};
const length = arr.len; // 3


3. 多维数组

Zig 支持 多维数组,但维度必须在编译时确定。

🔹 2D 数组示例

const matrix: [2][3]i32 = [2][3]i32{
    [3]i32{1, 2, 3},
    [3]i32{4, 5, 6},
};

pub fn main() void {
    std.debug.print("matrix[1][2]: {}\n", .{matrix[1][2]}); // 输出: 6
}

  • [2][3]i322 行 3 列的整数矩阵。
  • matrix[1][2] 访问 第 2 行第 3 列的值(6)

4. 切片基础

切片(Slice) 是数组的引用,大小可以动态变化,但 本质上仍然是指针,没有独立的存储空间。

🔹 定义切片

const arr = [_]i32{10, 20, 30, 40, 50};
const slice: []const i32 = arr[1..4]; // 取索引 1 到 3 的元素

  • arr[1..4]从索引 14(不包含 4
  • slice 指向 [20, 30, 40],但不复制数据。

🔹 访问切片元素

const std = @import("std");

pub fn main() void {
    const arr = [_]i32{1, 2, 3, 4, 5};
    const slice = arr[1..4]; // [2, 3, 4]

    for (slice) |value| {
        std.debug.print("{}\n", .{value});
    }
}

切片只是数组的一个视图,不能修改原始数组的大小!


5. 切片操作

🔹 获取切片长度

const slice = arr[1..4];
const length = slice.len; // 3

🔹 通过索引访问切片

const val = slice[0]; // 2

🔹 修改切片(可变切片)

如果切片是可变的(var 定义),可以修改元素:

var arr = [_]i32{1, 2, 3, 4, 5};
var slice = arr[1..4]; // [2, 3, 4]

slice[0] = 100; // 修改 arr[1]


6. 动态分配切片(std.ArrayList)

Zig 的数组大小固定,但可以使用 std.ArrayList 来实现动态数组。

🔹 使用 std.ArrayList

const std = @import("std");

pub fn main() void {
    var gpa = std.heap.page_allocator;
    var list = std.ArrayList(i32).init(gpa);

    list.append(10) catch unreachable;
    list.append(20) catch unreachable;
    list.append(30) catch unreachable;

    std.debug.print("动态数组: {}\n", .{list.items});
    
    list.deinit(); // 释放内存
}

  • std.ArrayList(i32):创建动态数组。
  • append(value):追加元素。
  • list.items:访问存储的切片。
  • deinit():释放分配的内存。

7. 数组 vs. 切片

特性数组切片
大小固定动态
内存直接存储数据指向数组的一部分
可变性不可改变大小可指向不同的数组部分
性能更快稍慢(指针访问)
动态分配✅(std.ArrayList

8. 参考资料