复合类型 #
一、数组 #
1.1 数组声明 #
zig
const std = @import("std");
pub fn main() void {
// 完整声明
const arr1: [5]i32 = [5]i32{ 1, 2, 3, 4, 5 };
// 类型推断
const arr2 = [_]i32{ 1, 2, 3, 4, 5 };
// 指定大小
const arr3 = [5]i32{ 1, 2, 3, 4, 5 };
std.debug.print("arr1 len: {}\n", .{arr1.len});
std.debug.print("arr2 len: {}\n", .{arr2.len});
std.debug.print("arr3 len: {}\n", .{arr3.len});
}
1.2 数组初始化 #
zig
const std = @import("std");
pub fn main() void {
// 列表初始化
const arr1 = [_]i32{ 1, 2, 3 };
// 重复初始化
const arr2 = [_]i32{0} ** 5;
// 部分初始化(其余为零)
const arr3 = [_]i32{ 1, 2 } ++ [_]i32{0} ** 3;
// 使用 for 循环初始化
var arr4: [5]i32 = undefined;
for (&arr4, 0..) |*item, i| {
item.* = @intCast(i * i);
}
std.debug.print("arr1: {any}\n", .{arr1});
std.debug.print("arr2: {any}\n", .{arr2});
std.debug.print("arr3: {any}\n", .{arr3});
std.debug.print("arr4: {any}\n", .{arr4});
}
1.3 数组访问 #
zig
const std = @import("std");
pub fn main() void {
const arr = [_]i32{ 10, 20, 30, 40, 50 };
// 索引访问
std.debug.print("arr[0] = {}\n", .{arr[0]});
std.debug.print("arr[4] = {}\n", .{arr[4]});
// 边界检查(编译时)
// std.debug.print("arr[5] = {}\n", .{arr[5]}); // 编译错误
// 运行时边界检查
var i: usize = 0;
i = 3;
std.debug.print("arr[i] = {}\n", .{arr[i]});
}
1.4 数组遍历 #
zig
const std = @import("std");
pub fn main() void {
const arr = [_]i32{ 10, 20, 30, 40, 50 };
// 遍历值
for (arr) |value| {
std.debug.print("{} ", .{value});
}
std.debug.print("\n", .{});
// 遍历值和索引
for (arr, 0..) |value, i| {
std.debug.print("arr[{}] = {}\n", .{ i, value });
}
// 遍历指针(可修改)
var mutable_arr = [_]i32{ 1, 2, 3, 4, 5 };
for (&mutable_arr) |*item| {
item.* *= 2;
}
std.debug.print("modified: {any}\n", .{mutable_arr});
}
1.5 多维数组 #
zig
const std = @import("std");
pub fn main() void {
// 二维数组
const matrix: [3][3]i32 = [3][3]i32{
.{ 1, 2, 3 },
.{ 4, 5, 6 },
.{ 7, 8, 9 },
};
std.debug.print("matrix[0][0] = {}\n", .{matrix[0][0]});
std.debug.print("matrix[1][1] = {}\n", .{matrix[1][1]});
// 遍历二维数组
for (matrix, 0..) |row, i| {
for (row, 0..) |val, j| {
std.debug.print("[{}][{}] = {} ", .{ i, j, val });
}
std.debug.print("\n", .{});
}
}
二、切片 #
2.1 切片基础 #
切片是对数组或另一个切片的视图:
zig
const std = @import("std");
pub fn main() void {
var arr = [_]i32{ 1, 2, 3, 4, 5 };
// 创建切片
const slice1: []i32 = arr[0..];
const slice2: []i32 = arr[1..4];
const slice3: []i32 = arr[0..arr.len];
std.debug.print("slice1 len: {}\n", .{slice1.len});
std.debug.print("slice2: {any}\n", .{slice2});
std.debug.print("slice3 len: {}\n", .{slice3.len});
}
2.2 切片操作 #
zig
const std = @import("std");
pub fn main() void {
var arr = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var slice: []i32 = arr[0..];
// 修改切片元素
slice[0] = 100;
// 切片再切片
const sub_slice = slice[2..5];
std.debug.print("slice: {any}\n", .{slice});
std.debug.print("sub_slice: {any}\n", .{sub_slice});
}
2.3 切片与指针 #
zig
const std = @import("std");
pub fn main() void {
var arr = [_]i32{ 1, 2, 3, 4, 5 };
// 可变切片
var slice: []i32 = arr[0..];
// 只读切片
const const_slice: []const i32 = arr[0..];
// 修改可变切片
slice[0] = 100;
// 不能修改只读切片
// const_slice[0] = 100; // 编译错误
std.debug.print("arr: {any}\n", .{arr});
}
2.4 切片指针 #
zig
const std = @import("std");
pub fn main() void {
var arr = [_]i32{ 1, 2, 3, 4, 5 };
// 切片指针(包含长度信息)
const slice_ptr: [*]i32 = &arr;
// 访问元素
std.debug.print("slice_ptr[0] = {}\n", .{slice_ptr[0]});
std.debug.print("slice_ptr[1] = {}\n", .{slice_ptr[1]});
// 注意:切片指针没有长度信息,需要手动管理
}
2.5 切片遍历 #
zig
const std = @import("std");
pub fn main() void {
var arr = [_]i32{ 10, 20, 30, 40, 50 };
var slice: []i32 = arr[1..4];
// 遍历值
for (slice) |value| {
std.debug.print("{} ", .{value});
}
std.debug.print("\n", .{});
// 遍历并修改
for (slice) |*item| {
item.* += 5;
}
std.debug.print("modified slice: {any}\n", .{slice});
std.debug.print("original arr: {any}\n", .{arr});
}
三、元组 #
3.1 元组基础 #
元组是匿名的结构体,可以包含不同类型的元素:
zig
const std = @import("std");
pub fn main() void {
// 创建元组
const tuple = .{ 1, "hello", 3.14, true };
// 访问元素
std.debug.print("tuple[0] = {}\n", .{tuple[0]});
std.debug.print("tuple[1] = {s}\n", .{tuple[1]});
std.debug.print("tuple[2] = {d}\n", .{tuple[2]});
std.debug.print("tuple[3] = {}\n", .{tuple[3]});
}
3.2 元组解构 #
zig
const std = @import("std");
pub fn main() void {
const tuple = .{ 10, "Zig", 3.14 };
// 解构
const a, const b, const c = tuple;
std.debug.print("a = {}\n", .{a});
std.debug.print("b = {s}\n", .{b});
std.debug.print("c = {d}\n", .{c});
}
3.3 元组遍历 #
zig
const std = @import("std");
pub fn main() void {
const tuple = .{ 1, "hello", 3.14, true };
// 使用 inline for 遍历
inline for (tuple, 0..) |value, i| {
std.debug.print("tuple[{}] = {} (type: {})\n", .{
i,
value,
@TypeOf(value),
});
}
}
3.4 元组作为函数参数 #
zig
const std = @import("std");
fn printTuple(tuple: anytype) void {
const fields = @typeInfo(@TypeOf(tuple)).@"struct".fields;
inline for (fields, 0..) |field, i| {
std.debug.print("field[{}] = {} (type: {})\n", .{
i,
@field(tuple, field.name),
field.type,
});
}
}
pub fn main() void {
const my_tuple = .{ 42, "Zig", 3.14 };
printTuple(my_tuple);
}
四、数组与切片转换 #
4.1 数组转切片 #
zig
const std = @import("std");
pub fn main() void {
var arr = [_]i32{ 1, 2, 3, 4, 5 };
// 完整切片
const slice1: []i32 = arr[0..];
const slice2: []i32 = &arr;
// 部分切片
const slice3: []i32 = arr[1..4];
std.debug.print("slice1 len: {}\n", .{slice1.len});
std.debug.print("slice2 len: {}\n", .{slice2.len});
std.debug.print("slice3 len: {}\n", .{slice3.len});
}
4.2 切片转数组 #
zig
const std = @import("std");
pub fn main() void {
var arr = [_]i32{ 1, 2, 3, 4, 5 };
const slice: []i32 = arr[0..3];
// 切片转数组(需要编译时已知长度)
const arr2: [3]i32 = slice[0..3].*;
std.debug.print("arr2: {any}\n", .{arr2});
}
五、常用操作 #
5.1 数组连接 #
zig
const std = @import("std");
pub fn main() void {
const arr1 = [_]i32{ 1, 2, 3 };
const arr2 = [_]i32{ 4, 5, 6 };
// 数组连接
const combined = arr1 ++ arr2;
std.debug.print("combined: {any}\n", .{combined});
}
5.2 数组重复 #
zig
const std = @import("std");
pub fn main() void {
const arr = [_]i32{ 1, 2 };
// 数组重复
const repeated = arr ** 3;
std.debug.print("repeated: {any}\n", .{repeated});
}
5.3 搜索元素 #
zig
const std = @import("std");
pub fn main() void {
const arr = [_]i32{ 10, 20, 30, 40, 50 };
// 查找元素
for (arr, 0..) |value, i| {
if (value == 30) {
std.debug.print("Found 30 at index {}\n", .{i});
break;
}
}
// 使用 std.mem.indexOf
const slice: []const i32 = &arr;
if (std.mem.indexOfScalar(i32, slice, 30)) |i| {
std.debug.print("Found 30 at index {}\n", .{i});
}
}
5.4 排序 #
zig
const std = @import("std");
pub fn main() void {
var arr = [_]i32{ 5, 2, 8, 1, 9, 3 };
// 排序
std.sort.heap(i32, &arr, {}, std.sort.asc(i32));
std.debug.print("sorted: {any}\n", .{arr});
}
六、总结 #
复合类型要点:
| 类型 | 特点 |
|---|---|
| 数组 | 固定长度,编译时确定 |
| 切片 | 动态长度,运行时确定 |
| 元组 | 匿名结构体,可包含不同类型 |
下一步,让我们学习可选类型!
最后更新:2026-03-27