Zig 深度实战:向 AI 代码说「不」的系统编程语言——从 comptime 元编程到手动内存管理的完全指南(2026)
引言:一个「逆行」的语言,却越来越火
2026 年 5 月底,一条技术新闻引爆了程序员社区:Zig 语言正式宣布禁止提交任何 AI 辅助生成的代码。不是"不建议",不是"需要标注"——是彻底的、不可协商的禁止。Zig 的贡献规则写得很清楚:不接受任何由大语言模型生成的内容,也不接受由大语言模型改写、润色、编辑、头脑风暴或调试过的内容。
在 AI 编程工具席卷整个行业的 2026 年,这个决定堪称"逆行"。连 Linux 之父 Linus Torvalds 都已经在个人项目中使用 AI 编程了,Zig 凭什么这么硬气?
答案藏在 Zig 的设计哲学里。这个语言从诞生的第一天起,就信奉一个原则:代码必须是人类可推理的。每一个字节、每一次内存分配、每一个类型转换,都必须是程序员有意识的选择。这种哲学不仅让 Zig 成为 C 语言最有力的替代者,更让它在操作系统开发、嵌入式系统、游戏引擎等底层领域迅速崛起。
本文将从零开始,带你深入理解 Zig 的核心设计,用大量代码实战演示它的独特能力,并探讨一个更深层的问题:在 AI 时代,我们是否还需要"人类可控"的编程语言?
一、Zig 是什么?为什么要学它?
1.1 定位:C 的替代者,不是 C 的包装者
Zig 由 Andrew Kelley 于 2016 年发起,定位非常明确:做一个比 C 更好的 C。但不同于 C++ 的思路(在 C 之上加无穷的抽象),Zig 选择了另一条路——做减法。
C 的痛点 → Zig 的解法
手动内存管理容易出错 → 更好的内存管理原语,无隐藏分配
宏系统不可调试 → comptime 元编程,类型安全的编译期计算
头文件地狱 → 单一文件模块系统,无头文件
构建系统碎片化 → 内置构建系统 zig build
错误处理混乱 → 显式错误集,强制处理
C 互操作痛苦 → 直接 import C,无需 FFI
Zig 不是在 C 上面包一层,而是重新思考"系统编程语言应该长什么样"。
1.2 生态现状(2026)
截至 2026 年 6 月,Zig 的生态已经相当成熟:
- Bun:用 Zig 编写的 JavaScript 运行时,npm 下载量超过 5 亿次
- TigerBeetle:金融级分布式数据库,用 Zig 编写,零依赖
- Mach Engine:用 Zig 编写的游戏引擎,对标 Unity/Unreal 的底层
- Bun 2.0:2025 年底发布,性能继续碾压 Node.js
- Zig 0.14:当前稳定版本,计划在 1.0 之前完成最后几个重大特性
Zig 的 GitHub Star 数已超过 38K,贡献者遍布全球。在系统编程领域,它已经成为 Rust 之外最值得关注的新选择。
1.3 Zig vs Rust:不同的哲学
很多人会问:已经有了 Rust,为什么还需要 Zig?
| 维度 | Rust | Zig |
|---|---|---|
| 内存安全 | 编译期借用检查器 | 手动管理,无隐藏分配 |
| 学习曲线 | 陡峭(生命周期、trait) | 平缓(概念少,显式为主) |
| 编译速度 | 慢(尤其是大型项目) | 快(增量编译友好) |
| C 互操作 | 通过 FFI bindgen | 直接 import C |
| 元编程 | 宏(macro_rules! / proc_macro) | comptime(编译期 Zig 代码) |
| 抽象能力 | trait、泛型、关联类型 | comptime 泛型、编译期接口 |
| 运行时开销 | 最小(但有权宜之便) | 零(无隐藏控制流) |
Rust 追求编译期证明安全,Zig 追求人类可推理的控制。这不是谁比谁好的问题,而是不同的设计权衡。
二、环境搭建与第一个程序
2.1 安装 Zig
# macOS
brew install zig
# Linux
curl -L https://ziglang.org/download/0.14.0/zig-linux-x86_64-0.14.0.tar.xz | tar -xJ
export PATH=$PWD/zig-linux-x86_64-0.14.0:$PATH
# Windows
winget install zig.zig
# 验证安装
zig version
# 0.14.0
2.2 初始化项目
mkdir zig-deep-dive && cd zig-deep-dive
zig init
# 项目结构
# .
# ├── build.zig # 构建脚本(Zig 代码,不是 Makefile)
# ├── build.zig.zon # 包管理配置
# └── src/
# ├── main.zig # 入口
# └── root.zig # 库根
2.3 Hello, World!
// src/main.zig
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("Hello, Zig!\n", .{});
}
运行:
zig build run
# Hello, Zig!
注意到几个细节:
!void表示这个函数可能返回错误(错误联合类型)try是错误传播操作符,类似 Go 的if err != nil但更简洁.{}是匿名结构体字面量,这里用于格式化参数
2.4 直接运行单文件
Zig 支持像脚本一样直接运行:
zig run hello.zig
这对快速实验和教学非常友好。
三、核心概念一:comptime——编译期计算的终极形态
comptime 是 Zig 最具革命性的特性。它不是宏,不是模板,不是代码生成——它就是普通的 Zig 代码,只是在编译期执行。
3.1 comptime 基础
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
// comptime 块中的代码在编译期执行
comptime {
const x = 10;
const y = 20;
// 这些计算在编译期完成,运行时零开销
std.debug.assert(x + y == 30);
}
// comptime 变量
const compile_time_value = comptime blk: {
var sum: u32 = 0;
var i: u32 = 1;
while (i <= 100) : (i += 1) {
sum += i;
}
break :blk sum; // 5050,编译期算出
};
try stdout.print("1到100的和 = {}\n", .{compile_time_value});
}
3.2 comptime 泛型:比 C++ 模板更优雅
在 C++ 中,泛型是模板,模板是代码生成,代码生成是宏的升级版——层层包装,调试困难。在 Zig 中,泛型就是接受 comptime 参数的普通函数:
const std = @import("std");
// 一个通用的 Vec2 类型
fn Vec2(comptime T: type) type {
return struct {
x: T,
y: T,
pub fn init(x: T, y: T) @This() {
return .{ .x = x, .y = y };
}
pub fn add(self: @This(), other: @This()) @This() {
return .{ .x = self.x + other.x, .y = self.y + other.y };
}
pub fn length(self: @This()) T {
// comptime 分派:整数类型不用 sqrt
switch (@typeInfo(T)) {
.int => |int_info| {
if (int_info.signedness == .unsigned) {
return self.x * self.x + self.y * self.y;
}
},
.float => {
return @sqrt(self.x * self.x + self.y * self.y);
},
else => @compileError("Vec2 only supports int and float types"),
}
}
pub fn format(
self: @This(),
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = fmt;
_ = options;
try writer.print("Vec2({d}, {d})", .{ self.x, self.y });
}
};
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
// 编译期生成不同的 Vec2 类型
const v1 = Vec2(f64).init(3.0, 4.0);
try stdout.print("f64 Vec2: {}, length = {d}\n", .{ v1, v1.length() });
const v2 = Vec2(u32).init(3, 4);
try stdout.print("u32 Vec2: {}, length² = {}\n", .{ v2, v2.length() });
// 不同类型的 Vec2 互不干扰
const v3 = Vec2(f32).init(1.5, 2.5);
const v4 = Vec2(f32).init(0.5, 0.5);
const v5 = v3.add(v4);
try stdout.print("f32 Vec2 add: {}, length = {d}\n", .{ v5, v5.length() });
// 尝试不支持的类型会编译报错
// const bad = Vec2(bool).init(true, false); // 编译错误!
}
关键点:
fn Vec2(comptime T: type) type—— 这是一个返回类型的函数comptime T: type表示 T 在编译期必须是已知类型- 整个函数体在编译期执行,生成具体的结构体
@typeInfo在编译期检查类型信息,实现类型安全的分派@compileError在编译期报错,而不是运行时崩溃
3.3 comptime 与类型系统深度结合
const std = @import("std");
// 编译期生成矩阵类型
fn Matrix(comptime T: type, comptime rows: usize, comptime cols: usize) type {
return [rows][cols]T;
}
// 编译期生成矩阵乘法函数(只对合法维度)
fn matMul(
comptime T: type,
comptime M: usize,
comptime N: usize,
comptime P: usize,
) fn (Matrix(T, M, N), Matrix(T, N, P)) Matrix(T, M, P) {
return struct {
fn mul(a: Matrix(T, M, N), b: Matrix(T, N, P)) Matrix(T, M, P) {
var result: Matrix(T, M, P) = undefined;
for (0..M) |i| {
for (0..P) |j| {
var sum: T = 0;
for (0..N) |k| {
sum += a[i][k] * b[k][j];
}
result[i][j] = sum;
}
}
return result;
}
}.mul;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const Mat2x3 = Matrix(f64, 2, 3);
const Mat3x2 = Matrix(f64, 3, 2);
const a: Mat2x3 = .{
.{ 1.0, 2.0, 3.0 },
.{ 4.0, 5.0, 6.0 },
};
const b: Mat3x2 = .{
.{ 7.0, 8.0 },
.{ 9.0, 10.0 },
.{ 11.0, 12.0 },
};
const multiply = matMul(f64, 2, 3, 2);
const c = multiply(a, b);
for (c) |row| {
for (row) |val| {
try stdout.print("{d:8.1} ", .{val});
}
try stdout.print("\n", .{});
}
// 输出:
// 58.0 64.0
// 139.0 154.0
// 维度不匹配的乘法直接编译报错!
// const bad = matMul(f64, 2, 3, 2);
// bad(a, a); // 编译错误:类型不匹配
}
3.4 comptime 字符串解析
这是 Zig 最惊艳的能力之一——你可以在编译期解析字符串:
const std = @import("std");
// 编译期解析版本号字符串
const SemanticVersion = struct {
major: u32,
minor: u32,
patch: u32,
};
fn parseVersion(comptime version_str: []const u8) SemanticVersion {
// 在编译期分割字符串
var parts: [3][]const u8 = undefined;
var part_idx: usize = 0;
var start: usize = 0;
for (version_str, 0..) |ch, i| {
if (ch == '.') {
parts[part_idx] = version_str[start..i];
part_idx += 1;
start = i + 1;
}
}
parts[part_idx] = version_str[start..];
return .{
.major = comptime std.fmt.parseInt(u32, parts[0], 10) catch
@compileError("Invalid major version"),
.minor = comptime std.fmt.parseInt(u32, parts[1], 10) catch
@compileError("Invalid minor version"),
.patch = comptime std.fmt.parseInt(u32, parts[2], 10) catch
@compileError("Invalid patch version"),
};
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
// 编译期解析
const version = comptime parseVersion("2.1.37");
try stdout.print("Version: {}.{}.{}\n", .{
version.major,
version.minor,
version.patch,
});
// 输出: Version: 2.1.37
// 无效版本号会在编译时报错
// const bad = comptime parseVersion("not.a.version");
}
3.5 comptime 生成代码:零成本抽象的终极形态
const std = @import("std");
// 编译期生成状态机
fn StateMachine(
comptime State: type,
comptime Event: type,
comptime transitions: []const struct {
from: State,
event: Event,
to: State,
},
) type {
// 编译期构建转换表
const TransitionTable = std.enums.EnumMap(State, std.enums.EnumMap(Event, State));
return struct {
current: State,
const Self = @This();
pub fn init(initial: State) Self {
return .{ .current = initial };
}
pub fn process(self: *Self, event: Event) !void {
// comptime 构建查表逻辑
inline for (transitions) |t| {
if (t.from == self.current and t.event == event) {
self.current = t.to;
return;
}
}
return error.InvalidTransition;
}
};
}
const DoorState = enum { open, closed, locked };
const DoorEvent = enum { open, close, lock, unlock };
const Door = StateMachine(DoorState, DoorEvent, &.{
.{ .from = .closed, .event = .open, .to = .open },
.{ .from = .open, .event = .close, .to = .closed },
.{ .from = .closed, .event = .lock, .to = .locked },
.{ .from = .locked, .event = .unlock, .to = .closed },
});
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
var door = Door.init(.closed);
try stdout.print("Door: {}\n", .{door.current}); // closed
try door.process(.lock);
try stdout.print("After lock: {}\n", .{door.current}); // locked
try door.process(.unlock);
try stdout.print("After unlock: {}\n", .{door.current}); // closed
try door.process(.open);
try stdout.print("After open: {}\n", .{door.current}); // open
// 无效转换会返回错误
const result = door.process(.lock); // 不能从 open 直接 lock
try stdout.print("Invalid transition result: {}\n", .{result == error.InvalidTransition});
}
这段代码的精妙之处在于:整个状态机的转换逻辑在编译期就已经固化,运行时只有一次 switch 比较。没有任何虚函数表、没有哈希查找、没有动态分派。这就是 Zig 式的零成本抽象。
四、核心概念二:手动内存管理——不藏不掖的内存控制
Zig 最核心的设计决策之一:没有隐藏的内存分配。每一个可能分配内存的操作,都必须显式传入分配器。这意味着你可以精确追踪程序的每一字节内存。
4.1 分配器体系
Zig 提供了多种分配器,每种都有明确的使用场景:
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
// 1. GPA (General Purpose Allocator) - 生产环境首选
// 检测内存泄漏、双重释放、越界访问
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit(); // 程序结束时检查泄漏
const allocator = gpa.allocator();
// 2. Arena 分配器 - 批量释放,适合临时计算
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit(); // 一次释放所有
const arena_allocator = arena.allocator();
// 3. 固定缓冲区分配器 - 嵌入式/实时系统
var buffer: [1024]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const fba_allocator = fba.allocator();
// 使用分配器分配内存
const slice = try allocator.alloc(u8, 100);
defer allocator.free(slice); // 必须手动释放
const arena_slice = try arena_allocator.alloc(u8, 200);
// 不需要单独 free,arena.deinit() 会统一释放
const fba_slice = try fba_allocator.alloc(u8, 50);
// 不需要 free,buffer 在栈上,函数返回自动回收
try stdout.print("GPA allocated: {} bytes\n", .{slice.len});
try stdout.print("Arena allocated: {} bytes\n", .{arena_slice.len});
try stdout.print("FBA allocated: {} bytes\n", .{fba_slice.len});
}
4.2 GPA 的内存安全检测
GPA 是 Zig 内存安全的第一道防线:
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{
.safety = true, // 开启安全检测(Debug 模式默认开启)
}){};
defer {
const leaked = gpa.deinit();
if (leaked == .leak) {
std.log.err("Memory leak detected!", .{});
}
}
const allocator = gpa.allocator();
// 正常分配和释放
const data = try allocator.alloc(u32, 10);
allocator.free(data);
// 故意泄漏 - 程序结束时 GPA 会报告
const leaked_data = try allocator.alloc(u32, 5);
_ = leaked_data; // 没有 free!
// GPA 的 deinit 会检测到这个泄漏
}
4.3 实战:用 Zig 构建一个简单的动态数组
const std = @import("std");
fn ArrayList(comptime T: type) type {
return struct {
items: []T,
capacity: usize,
len: usize,
allocator: std.mem.Allocator,
const Self = @This();
pub fn init(allocator: std.mem.Allocator) Self {
return .{
.items = &.{},
.capacity = 0,
.len = 0,
.allocator = allocator,
};
}
pub fn deinit(self: *Self) void {
if (self.capacity > 0) {
self.allocator.free(self.items);
}
}
pub fn append(self: *Self, item: T) !void {
if (self.len >= self.capacity) {
const new_capacity = if (self.capacity == 0) 4 else self.capacity * 2;
const new_items = try self.allocator.alloc(T, new_capacity);
// 复制旧数据
if (self.len > 0) {
@memcpy(new_items[0..self.len], self.items);
self.allocator.free(self.items);
}
self.items = new_items;
self.capacity = new_capacity;
}
self.items[self.len] = item;
self.len += 1;
}
pub fn get(self: Self, index: usize) ?T {
if (index >= self.len) return null;
return self.items[index];
}
pub fn slice(self: Self) []const T {
return self.items[0..self.len];
}
};
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const stdout = std.io.getStdOut().writer();
var list = ArrayList(u32).init(allocator);
defer list.deinit();
// 追加元素
for (0..20) |i| {
try list.append(@intCast(i * i));
}
// 遍历
try stdout.print("Square numbers: ", .{});
for (list.slice()) |val| {
try stdout.print("{} ", .{val});
}
try stdout.print("\n", .{});
// 随机访问
if (list.get(5)) |val| {
try stdout.print("list[5] = {}\n", .{val}); // 25
}
}
注意:Zig 标准库已经有 std.ArrayList,这里手写是为了展示内存管理的细节。实际开发中直接用标准库的版本。
4.4 自定义分配器:日志分配器
Zig 的分配器是接口,你可以创建自定义实现:
const std = @import("std");
// 包装一个分配器,记录每次分配
const LoggingAllocator = struct {
parent: std.mem.Allocator,
alloc_count: usize = 0,
free_count: usize = 0,
total_bytes: usize = 0,
const Self = @This();
pub fn init(parent: std.mem.Allocator) Self {
return .{ .parent = parent };
}
pub fn allocator(self: *Self) std.mem.Allocator {
return .{
.ptr = self,
.vtable = &.{
.alloc = alloc,
.resize = resize,
.free = free,
},
};
}
fn alloc(
ctx: *anyopaque,
len: usize,
log2_ptr_align: u8,
return_address: usize,
) ?[*]u8 {
const self: *Self = @ptrCast(@alignCast(ctx));
const result = self.parent.rawAlloc(len, log2_ptr_align, return_address);
if (result) |ptr| {
self.alloc_count += 1;
self.total_bytes += len;
std.log.info("ALLOC: {} bytes at {*}", .{ len, ptr });
}
return result;
}
fn resize(
ctx: *anyopaque,
buf: []u8,
log2_buf_align: u8,
new_len: usize,
return_address: usize,
) bool {
const self: *Self = @ptrCast(@alignCast(ctx));
return self.parent.rawResize(buf, log2_buf_align, new_len, return_address);
}
fn free(
ctx: *anyopaque,
buf: []u8,
log2_buf_align: u8,
return_address: usize,
) void {
const self: *Self = @ptrCast(@alignCast(ctx));
self.free_count += 1;
std.log.info("FREE: {} bytes at {*}", .{ buf.len, buf.ptr });
self.parent.rawFree(buf, log2_buf_align, return_address);
}
pub fn report(self: Self) void {
std.log.info("=== Allocation Report ===", .{});
std.log.info(" Allocations: {}", .{self.alloc_count});
std.log.info(" Frees: {}", .{self.free_count});
std.log.info(" Total bytes allocated: {}", .{self.total_bytes});
std.log.info(" Leaks: {}", .{self.alloc_count - self.free_count});
}
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
var logger = LoggingAllocator.init(gpa.allocator());
defer logger.report();
const allocator = logger.allocator();
// 做一些分配
const s1 = try allocator.alloc(u8, 100);
allocator.free(s1);
const s2 = try allocator.alloc(u8, 256);
const s3 = try allocator.alloc(u8, 512);
allocator.free(s3);
allocator.free(s2);
// 报告:2 allocs, 2 frees, 0 leaks
}
五、核心概念三:错误处理——显式优于隐式
Zig 的错误处理设计哲学:错误是值,不是异常。没有 try-catch,没有隐藏的控制流跳转。
5.1 错误集
const std = @import("std");
// 定义错误集
const FileError = error{
NotFound,
PermissionDenied,
TooLarge,
InvalidFormat,
};
const NetworkError = error{
Timeout,
ConnectionRefused,
DnsResolutionFailed,
};
// 错误集可以自动合并
const AppError = FileError || NetworkError;
// 函数返回错误联合类型
fn readFile(path: []const u8) FileError![]const u8 {
if (path.len == 0) return error.NotFound;
if (std.mem.startsWith(u8, path, "/root")) return error.PermissionDenied;
// 模拟读取
return "file content";
}
fn fetchData(url: []const u8) NetworkError![]const u8 {
if (std.mem.startsWith(u8, url, "https://slow")) return error.Timeout;
return "data from network";
}
// 合并错误集的函数
fn loadConfig() AppError!void {
const content = try readFile("/etc/config");
_ = content;
const data = try fetchData("https://example.com/api");
_ = data;
}
5.2 errdefer:错误时的资源清理
这是 Zig 独有的特性,比 Go 的 defer 更精细:
const std = @import("std");
fn processFile(allocator: std.mem.Allocator, path: []const u8) !void {
const stdout = std.io.getStdOut().writer();
// 分配缓冲区
const buffer = try allocator.alloc(u8, 4096);
// 如果函数返回错误,自动释放 buffer
errdefer allocator.free(buffer);
// 打开文件
const file = try std.fs.cwd().openFile(path, .{});
// 如果后续出错,自动关闭文件
errdefer file.close();
// 读取文件
const bytes_read = try file.readAll(buffer);
try stdout.print("Read {} bytes\n", .{bytes_read});
// 正常退出时,errdefer 不会执行
// 但需要手动清理(因为函数成功时 errdefer 不触发)
allocator.free(buffer);
file.close();
}
5.3 错误处理的完整模式
const std = @import("std");
const Config = struct {
host: []const u8,
port: u16,
timeout_ms: u32,
};
const ConfigError = error{
MissingField,
InvalidPort,
InvalidTimeout,
OutOfMemory,
};
fn parseConfig(allocator: std.mem.Allocator, raw: []const u8) ConfigError!Config {
var host: ?[]const u8 = null;
var port: ?u16 = null;
var timeout: ?u32 = null;
// 简单的行解析
var lines = std.mem.splitSequence(u8, raw, "\n");
while (lines.next()) |line| {
if (line.len == 0 or line[0] == '#') continue;
if (std.mem.indexOf(u8, line, "=")) |eq_pos| {
const key = std.mem.trim(u8, line[0..eq_pos], " \t");
const val = std.mem.trim(u8, line[eq_pos + 1 ..], " \t");
if (std.mem.eql(u8, key, "host")) {
host = try allocator.dupe(u8, val);
} else if (std.mem.eql(u8, key, "port")) {
port = std.fmt.parseInt(u16, val, 10) catch
return error.InvalidPort;
} else if (std.mem.eql(u8, key, "timeout_ms")) {
timeout = std.fmt.parseInt(u32, val, 10) catch
return error.InvalidTimeout;
}
}
}
return .{
.host = host orelse return error.MissingField,
.port = port orelse return error.MissingField,
.timeout_ms = timeout orelse return error.MissingField,
};
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const stdout = std.io.getStdOut().writer();
const config_text =
\\host = 127.0.0.1
\\port = 8080
\\timeout_ms = 5000
;
const config = parseConfig(allocator, config_text) catch |err| {
try stdout.print("Config error: {}\n", .{err});
return;
};
try stdout.print("Config: host={s}, port={}, timeout={}ms\n", .{
config.host,
config.port,
config.timeout_ms,
});
}
六、核心概念四:与 C 的无缝互操作
这是 Zig 的杀手级特性。不需要 bindgen,不需要 FFI 绑定代码,直接 import C 头文件。
6.1 直接使用 C 库
const std = @import("std");
const c = @cImport({
@cInclude("stdio.h");
@cInclude("stdlib.h");
@cInclude("string.h");
});
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
// 直接调用 C 的 printf
_ = c.printf("Hello from C's printf!\n");
// 使用 C 的 malloc/free
const ptr = c.malloc(100);
if (ptr == null) return error.OutOfMemory;
defer c.free(ptr);
// 使用 C 的 memset
c.memset(ptr, 0, 100);
try stdout.print("Allocated and zeroed 100 bytes via C\n", .{});
}
6.2 构建 C 项目
build.zig 可以无缝编译 C 代码:
// build.zig
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOptions(.{});
// 编译 C 代码作为 Zig 项目的一部分
const exe = b.addExecutable(.{
.name = "myapp",
.target = target,
.optimize = optimize,
});
exe.addCSourceFile(.{
.file = .{ .path = "src/legacy_math.c" },
.flags = &.{"-Wall"},
});
exe.addIncludePath(.{ .path = "include" });
exe.linkLibC();
b.installArtifact(exe);
}
6.3 实战:用 Zig 包装 SQLite
const std = @import("std");
const c = @cImport({
@cInclude("sqlite3.h");
});
const Sqlite = struct {
db: *c.sqlite3,
const Self = @This();
pub const Error = error{
OpenFailed,
ExecFailed,
PrepareFailed,
StepFailed,
};
pub fn open(path: [*:0]const u8) Error!Self {
var db: ?*c.sqlite3 = null;
const rc = c.sqlite3_open(path, &db);
if (rc != c.SQLITE_OK) {
if (db) |d| c.sqlite3_close(d);
return error.OpenFailed;
}
return .{ .db = db.? };
}
pub fn close(self: *Self) void {
c.sqlite3_close(self.db);
}
pub fn exec(self: *Self, sql: [*:0]const u8) Error!void {
var err_msg: ?[*:0]u8 = null;
const rc = c.sqlite3_exec(self.db, sql, null, null, &err_msg);
if (rc != c.SQLITE_OK) {
if (err_msg) |msg| {
std.log.err("SQLite error: {s}", .{msg});
c.sqlite3_free(msg);
}
return error.ExecFailed;
}
}
pub fn querySingle(
self: *Self,
allocator: std.mem.Allocator,
sql: [*:0]const u8,
) Error!?[]const u8 {
var stmt: ?*c.sqlite3_stmt = null;
const rc = c.sqlite3_prepare_v2(
self.db,
sql,
-1,
&stmt,
null,
);
if (rc != c.SQLITE_OK) return error.PrepareFailed;
defer _ = c.sqlite3_finalize(stmt);
const step_rc = c.sqlite3_step(stmt);
if (step_rc == c.SQLITE_DONE) return null;
if (step_rc != c.SQLITE_ROW) return error.StepFailed;
const text = c.sqlite3_column_text(stmt, 0);
const len = c.sqlite3_column_bytes(stmt, 0);
return try allocator.dupe(u8, text[0..@intCast(len)]);
}
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const stdout = std.io.getStdOut().writer();
var db = try Sqlite.open(":memory:");
defer db.close();
try db.exec("CREATE TABLE users (name TEXT, age INTEGER)");
try db.exec("INSERT INTO users VALUES ('Alice', 30)");
try db.exec("INSERT INTO users VALUES ('Bob', 25)");
const result = try db.querySingle(allocator, "SELECT name FROM users WHERE age > 26");
if (result) |name| {
defer allocator.free(name);
try stdout.print("Found: {s}\n", .{name}); // Alice
}
}
七、核心概念五:并发与异步
Zig 的并发模型经历了一次重大重构。从最初基于事件循环的 async/await,转向了更底层、更可控的方式。
7.1 线程与互斥
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var mutex = std.Thread.Mutex{};
var counter: u64 = 0;
const WorkerContext = struct {
mutex: *std.Thread.Mutex,
counter: *u64,
iterations: u32,
};
const worker = struct {
fn run(ctx: WorkerContext) void {
var i: u32 = 0;
while (i < ctx.iterations) : (i += 1) {
ctx.mutex.lock();
defer ctx.mutex.unlock();
ctx.counter.* += 1;
}
}
};
const num_threads = 8;
const iterations = 100_000;
var threads = try allocator.alloc(std.Thread, num_threads);
defer allocator.free(threads);
var contexts = try allocator.alloc(WorkerContext, num_threads);
defer allocator.free(contexts);
// 启动线程
for (0..num_threads) |i| {
contexts[i] = .{
.mutex = &mutex,
.counter = &counter,
.iterations = iterations,
};
threads[i] = try std.Thread.spawn(
.{},
worker.run,
.{contexts[i]},
);
}
// 等待所有线程完成
for (threads) |thread| {
thread.join();
}
const stdout = std.io.getStdOut().writer();
try stdout.print("Counter: {} (expected: {})\n", .{
counter,
num_threads * iterations,
});
}
7.2 线程池
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const stdout = std.io.getStdOut().writer();
var pool = std.Thread.Pool{};
try pool.init(.{
.allocator = allocator,
.n_jobs = 4,
});
defer pool.deinit();
var wg = std.Thread.WaitGroup{};
const Task = struct {
id: u32,
stdout: std.io.getStdOut().Writer(),
pub fn run(self: @This()) void {
self.stdout.print("Task {} running on thread\n", .{self.id}) catch {};
}
};
for (0..10) |i| {
pool.spawnWg(&wg, Task.run, .{
Task{ .id = @intCast(i), .stdout = stdout },
});
}
wg.wait();
try stdout.print("All tasks completed\n", .{});
}
八、构建系统:zig build 详解
Zig 内置了完整的构建系统,不再需要 Makefile、CMake 或任何外部工具。
8.1 build.zig 基础
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOptions(.{});
// 可执行文件
const exe = b.addExecutable(.{
.name = "myapp",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
// 链接系统库
exe.linkSystemLibrary("sqlite3");
exe.linkLibC();
b.installArtifact(exe);
// 运行命令
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
// 单元测试
const unit_tests = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
const run_unit_tests = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_unit_tests.step);
}
8.2 交叉编译
Zig 的交叉编译开箱即用,不需要任何额外工具链:
# 为 Linux ARM64 编译
zig build -Dtarget=aarch64-linux-gnu
# 为 Windows x86_64 编译
zig build -Dtarget=x86_64-windows-gnu
# 为 macOS 编译
zig build -Dtarget=x86_64-macos
# 为 WebAssembly 编译
zig build -Dtarget=wasm32-freestanding
这在 CI/CD 中极其方便,一个命令搞定多平台构建。
九、性能实战:用 Zig 重写热点路径
让我们用一个实际案例来展示 Zig 的性能优势:JSON 解析。
9.1 高性能 JSON 解析
const std = @import("std");
// 简化版 JSON Token 解析器
const JsonToken = enum {
object_start, // {
object_end, // }
array_start, // [
array_end, // ]
string, // "..."
number, // 123 / 1.5
true_val, // true
false_val, // false
null_val, // null
colon, // :
comma, // ,
};
const JsonValue = union(JsonToken) {
object_start: void,
object_end: void,
array_start: void,
array_end: void,
string: []const u8,
number: f64,
true_val: void,
false_val: void,
null_val: void,
colon: void,
comma: void,
};
const JsonParser = struct {
input: []const u8,
pos: usize,
const Self = @This();
pub fn init(input: []const u8) Self {
return .{ .input = input, .pos = 0 };
}
pub fn next(self: *Self) ?JsonValue {
self.skipWhitespace();
if (self.pos >= self.input.len) return null;
const ch = self.input[self.pos];
switch (ch) {
'{' => {
self.pos += 1;
return .{ .object_start = {} };
},
'}' => {
self.pos += 1;
return .{ .object_end = {} };
},
'[' => {
self.pos += 1;
return .{ .array_start = {} };
},
']' => {
self.pos += 1;
return .{ .array_end = {} };
},
'"' => return self.parseString(),
':' => {
self.pos += 1;
return .{ .colon = {} };
},
',' => {
self.pos += 1;
return .{ .comma = {} };
},
't' => {
if (std.mem.startsWith(u8, self.input[self.pos..], "true")) {
self.pos += 4;
return .{ .true_val = {} };
}
return null;
},
'f' => {
if (std.mem.startsWith(u8, self.input[self.pos..], "false")) {
self.pos += 5;
return .{ .false_val = {} };
}
return null;
},
'n' => {
if (std.mem.startsWith(u8, self.input[self.pos..], "null")) {
self.pos += 4;
return .{ .null_val = {} };
}
return null;
},
'0'...'9', '-' => return self.parseNumber(),
else => return null,
}
}
fn skipWhitespace(self: *Self) void {
while (self.pos < self.input.len) : (self.pos += 1) {
switch (self.input[self.pos]) {
' ', '\t', '\n', '\r' => {},
else => break,
}
}
}
fn parseString(self: *Self) JsonValue {
self.pos += 1; // skip opening quote
const start = self.pos;
while (self.pos < self.input.len) : (self.pos += 1) {
if (self.input[self.pos] == '"') {
const str = self.input[start..self.pos];
self.pos += 1;
return .{ .string = str };
}
if (self.input[self.pos] == '\\') {
self.pos += 1; // skip escaped char
}
}
return .{ .string = "" }; // malformed
}
fn parseNumber(self: *Self) JsonValue {
const start = self.pos;
if (self.pos < self.input.len and self.input[self.pos] == '-') {
self.pos += 1;
}
while (self.pos < self.input.len and self.input[self.pos] >= '0' and self.input[self.pos] <= '9') {
self.pos += 1;
}
if (self.pos < self.input.len and self.input[self.pos] == '.') {
self.pos += 1;
while (self.pos < self.input.len and self.input[self.pos] >= '0' and self.input[self.pos] <= '9') {
self.pos += 1;
}
}
const num_str = self.input[start..self.pos];
const num = std.fmt.parseFloat(f64, num_str) catch 0;
return .{ .number = num };
}
};
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const json =
\\{"name":"Zig","version":0.14,"features":["comptime","manual_memory","c_interop"],"stable":true,"deprecated":null}
;
var parser = JsonParser.init(json);
try stdout.print("Tokenizing JSON:\n", .{});
while (parser.next()) |token| {
switch (token) {
.string => |s| try stdout.print(" STRING: \"{s}\"\n", .{s}),
.number => |n| try stdout.print(" NUMBER: {d}\n", .{n}),
.object_start => try stdout.print(" {{\n", .{}),
.object_end => try stdout.print(" }}\n", .{}),
.array_start => try stdout.print(" [\n", .{}),
.array_end => try stdout.print(" ]\n", .{}),
.true_val => try stdout.print(" TRUE\n", .{}),
.false_val => try stdout.print(" FALSE\n", .{}),
.null_val => try stdout.print(" NULL\n", .{}),
else => {},
}
}
}
9.2 SIMD 优化:字符串搜索
const std = @import("std");
// 使用 SIMD 加速字节搜索
fn indexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
// 在有 SIMD 支持的平台上,编译器会自动向量化这段代码
for (slice, 0..) |item, i| {
if (item == value) return i;
}
return null;
}
// 手动 SIMD 版本(x86_64 AVX2)
fn indexOfByteAVX2(haystack: []const u8, needle: u8) ?usize {
if (!std.Target.x86.featureSetHas(std.Target.current.cpu.features, .avx2)) {
return indexOfScalar(u8, haystack, needle);
}
const vec_size = 32; // AVX2 = 256 bit = 32 bytes
var i: usize = 0;
// 用广播填充目标字节
while (i + vec_size <= haystack.len) : (i += vec_size) {
const chunk = haystack[i..][0..vec_size].*;
var matches: u32 = 0;
// 展开比较
for (chunk, 0..) |byte, j| {
if (byte == needle) {
matches |= @as(u32, 1) << @intCast(j);
}
}
if (matches != 0) {
return i + @ctz(matches);
}
}
// 处理剩余部分
while (i < haystack.len) : (i += 1) {
if (haystack[i] == needle) return i;
}
return null;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const text = "The quick brown fox jumps over the lazy dog";
if (indexOfByteAVX2(text, 'f')) |idx| {
try stdout.print("Found 'f' at index {}\n", .{idx}); // 16
}
if (indexOfByteAVX2(text, 'z')) |idx| {
try stdout.print("Found 'z' at index {}\n", .{idx}); // 37
}
}
十、Zig 禁止 AI 代码:深层思考
10.1 事件的来龙去脉
2026 年 5 月,Zig 语言维护团队更新了贡献者行为准则,新增了一条规定:禁止提交任何由大语言模型生成或辅助生成的内容。这包括:
- 直接由 LLM 生成的代码
- 由 LLM 改写、润色或编辑的代码
- 由 LLM 头脑风暴产生的方案
- 由 LLM 调试修复的问题
这不是一个模糊的建议,而是一个硬性规则。违反这条规则的 PR 会被直接关闭。
10.2 Zig 团队的理由
Zig 团队的核心论点:
可推理性:Zig 的设计目标之一是让每一行代码都可以被人类完整推理。AI 生成的代码打破了这个假设——贡献者可能并不真正理解自己提交的代码。
质量保证:AI 生成的代码往往在表面看起来正确,但在边界情况下会出现微妙的问题。系统编程语言对正确性的要求极高,一个微小的内存错误可能导致安全漏洞。
许可和法律风险:AI 生成代码的版权归属尚不明确。Zig 采用 MIT 许可证,需要确保每个贡献者有权授予许可,AI 辅助的代码让这一点变得模糊。
社区文化:Zig 希望维护一个以人类理解和学习为核心的社区。AI 生成代码会降低社区的知识水平。
10.3 争议与反思
这个决定在社区引发了激烈讨论:
支持者认为:
- 系统编程需要人类对每一行代码的完全掌控
- AI 生成的代码可能引入难以发现的微妙的内存安全漏洞
- 这保护了项目免受"看起来正确但实际有 bug"的贡献
- 对于基础设施级软件,保守是正确的态度
反对者认为:
- 这把一个有用的工具拒之门外,降低了贡献效率
- 人类写的代码也有 bug,AI 辅助可以减少某些类型的错误
- 这可能导致贡献者减少,影响项目发展
- 如何执行这个规则?是否要检查每个 PR 的代码风格?
10.4 更深层的问题
Zig 的决定触及了一个根本性的问题:在系统编程领域,代码的正确性是否可以与作者的理解分离?
传统的软件工程认为,代码的质量取决于代码本身,而不是作者的意图。但在系统编程中,一个无法被作者完整推理的代码段,即使通过了所有测试,也可能在极端条件下产生灾难性后果。这不仅仅是关于 AI——它关乎我们如何看待系统软件的可靠性。
十一、实战项目:用 Zig 构建一个高性能 HTTP 服务器
让我们把前面学到的所有知识综合起来,构建一个完整的 HTTP 服务器。
11.1 项目结构
zig-http-server/
├── build.zig
├── build.zig.zon
└── src/
├── main.zig
├── server.zig
├── router.zig
├── request.zig
└── response.zig
11.2 HTTP 请求解析
// src/request.zig
const std = @import("std");
pub const Method = enum {
GET,
POST,
PUT,
DELETE,
PATCH,
HEAD,
OPTIONS,
pub fn fromString(str: []const u8) ?Method {
if (std.mem.eql(u8, str, "GET")) return .GET;
if (std.mem.eql(u8, str, "POST")) return .POST;
if (std.mem.eql(u8, str, "PUT")) return .PUT;
if (std.mem.eql(u8, str, "DELETE")) return .DELETE;
if (std.mem.eql(u8, str, "PATCH")) return .PATCH;
if (std.mem.eql(u8, str, "HEAD")) return .HEAD;
if (std.mem.eql(u8, str, "OPTIONS")) return .OPTIONS;
return null;
}
};
pub const Request = struct {
method: Method,
path: []const u8,
headers: std.StringHashMap([]const u8),
body: []const u8,
pub fn parse(allocator: std.mem.Allocator, raw: []const u8) !Request {
// 找到 header 结束位置
const header_end = std.mem.indexOf(u8, raw, "\r\n\r\n") orelse
return error.InvalidRequest;
const header_section = raw[0..header_end];
const body = if (header_end + 4 < raw.len) raw[header_end + 4 ..] else "";
// 解析请求行
var lines = std.mem.splitSequence(u8, header_section, "\r\n");
const request_line = lines.next() orelse return error.InvalidRequest;
var parts = std.mem.splitSequence(u8, request_line, " ");
const method_str = parts.next() orelse return error.InvalidRequest;
const path = parts.next() orelse return error.InvalidRequest;
const method = Method.fromString(method_str) orelse
return error.InvalidMethod;
// 解析 headers
var headers = std.StringHashMap([]const u8).init(allocator);
errdefer headers.deinit();
while (lines.next()) |line| {
if (std.mem.indexOf(u8, line, ": ")) |colon_pos| {
const key = line[0..colon_pos];
const value = line[colon_pos + 2 ..];
try headers.put(key, value);
}
}
return .{
.method = method,
.path = path,
.headers = headers,
.body = body,
};
}
pub fn deinit(self: *Request) void {
self.headers.deinit();
}
};
11.3 路由器
// src/router.zig
const std = @import("std");
const Request = @import("request.zig").Request;
pub const HandlerFn = *const fn (*Request) anyerror![]const u8;
pub const Route = struct {
method: @import("request.zig").Method,
path: []const u8,
handler: HandlerFn,
};
pub const Router = struct {
routes: std.ArrayList(Route),
allocator: std.mem.Allocator,
const Self = @This();
pub fn init(allocator: std.mem.Allocator) Self {
return .{
.routes = std.ArrayList(Route).init(allocator),
.allocator = allocator,
};
}
pub fn deinit(self: *Self) void {
self.routes.deinit();
}
pub fn add(self: *Self, method: @import("request.zig").Method, path: []const u8, handler: HandlerFn) !void {
try self.routes.append(.{
.method = method,
.path = path,
.handler = handler,
});
}
pub fn dispatch(self: *Self, request: *Request) ?HandlerFn {
for (self.routes.items) |route| {
if (route.method == request.method and
std.mem.eql(u8, route.path, request.path))
{
return route.handler;
}
}
return null;
}
};
11.4 服务器主体
// src/server.zig
const std = @import("std");
const Request = @import("request.zig").Request;
const Router = @import("router.zig").Router;
pub const Server = struct {
allocator: std.mem.Allocator,
router: Router,
address: std.net.Address,
const Self = @This();
pub fn init(allocator: std.mem.Allocator, port: u16) !Self {
return .{
.allocator = allocator,
.router = Router.init(allocator),
.address = try std.net.Address.resolveIp(.{ .sa = .{ .family = std.os.AF.INET } }, port),
};
}
pub fn deinit(self: *Self) void {
self.router.deinit();
}
pub fn get(self: *Self, path: []const u8, handler: @import("router.zig").HandlerFn) !void {
try self.router.add(.GET, path, handler);
}
pub fn post(self: *Self, path: []const u8, handler: @import("router.zig").HandlerFn) !void {
try self.router.add(.POST, path, handler);
}
pub fn listen(self: *Self) !void {
const stdout = std.io.getStdOut().writer();
const server_sock = try self.address.listen(.{
.reuse_address = true,
});
defer server_sock.deinit();
try stdout.print("Server listening on {}\n", .{self.address});
while (true) {
const conn = server_sock.accept() catch |err| {
std.log.err("Accept failed: {}", .{err});
continue;
};
defer conn.stream.close();
self.handleConnection(conn) catch |err| {
std.log.err("Handle connection failed: {}", .{err});
};
}
}
fn handleConnection(self: *Self, conn: std.net.Server.Connection) !void {
var buf: [8192]u8 = undefined;
const bytes_read = try conn.stream.read(&buf);
if (bytes_read == 0) return;
const raw_request = buf[0..bytes_read];
var request = try Request.parse(self.allocator, raw_request);
defer request.deinit();
const response = if (self.router.dispatch(&request)) |handler|
handler(&request) catch "500 Internal Server Error"
else
"404 Not Found";
const http_response = std.fmt.allocPrint(
self.allocator,
"HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: {}\r\n\r\n{s}",
.{ response.len, response },
) catch "HTTP/1.1 500 Internal Server Error\r\n\r\n";
defer self.allocator.free(http_response);
_ = try conn.stream.writeAll(http_response);
}
};
11.5 main.zig——组装一切
// src/main.zig
const std = @import("std");
const Server = @import("server.zig").Server;
const Request = @import("request.zig").Request;
fn handleIndex(request: *Request) anyerror![]const u8 {
_ = request;
return "Welcome to Zig HTTP Server!";
}
fn handleHealth(request: *Request) anyerror![]const u8 {
_ = request;
return "{\"status\":\"ok\",\"uptime\":12345}";
}
fn handleEcho(request: *Request) anyerror![]const u8 {
if (request.body.len > 0) {
return request.body;
}
return "Send a POST body to echo it back";
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var server = try Server.init(allocator, 8080);
defer server.deinit();
try server.get("/", handleIndex);
try server.get("/health", handleHealth);
try server.post("/echo", handleEcho);
try server.listen();
}
11.6 构建与运行
zig build run
# Server listening on 127.0.0.1:8080
# 另一个终端
curl http://localhost:8080/
# Welcome to Zig HTTP Server!
curl http://localhost:8080/health
# {"status":"ok","uptime":12345}
curl -X POST -d "Hello, Zig!" http://localhost:8080/echo
# Hello, Zig!
十二、Zig 的测试体系
Zig 内置了测试框架,不需要任何第三方库。
12.1 基础测试
const std = @import("std");
// 被测试的函数
fn fibonacci(n: u32) u64 {
if (n <= 1) return n;
var a: u64 = 0;
var b: u64 = 1;
var i: u32 = 2;
while (i <= n) : (i += 1) {
const temp = a + b;
a = b;
b = temp;
}
return b;
}
// 测试用例
test "fibonacci base cases" {
try std.testing.expectEqual(@as(u64, 0), fibonacci(0));
try std.testing.expectEqual(@as(u64, 1), fibonacci(1));
}
test "fibonacci small values" {
try std.testing.expectEqual(@as(u64, 1), fibonacci(2));
try std.testing.expectEqual(@as(u64, 2), fibonacci(3));
try std.testing.expectEqual(@as(u64, 3), fibonacci(4));
try std.testing.expectEqual(@as(u64, 5), fibonacci(5));
try std.testing.expectEqual(@as(u64, 8), fibonacci(6));
}
test "fibonacci larger values" {
try std.testing.expectEqual(@as(u64, 55), fibonacci(10));
try std.testing.expectEqual(@as(u64, 6765), fibonacci(20));
}
// 测试分配器
test "allocator usage" {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const slice = try allocator.alloc(u32, 10);
defer allocator.free(slice);
for (slice, 0..) |*item, i| {
item.* = @intCast(i);
}
try std.testing.expectEqual(@as(u32, 0), slice[0]);
try std.testing.expectEqual(@as(u32, 9), slice[9]);
}
12.2 运行测试
# 运行所有测试
zig build test
# 运行特定测试
zig test src/main.zig --test-filter "fibonacci"
# 带内存泄漏检测
zig test src/main.zig -Doptimize=Debug
12.3 基准测试
const std = @import("std");
fn benchmark(allocator: std.mem.Allocator, comptime func: anytype, args: anytype, iterations: u32) !u64 {
const start = std.time.nanoTimestamp();
for (0..iterations) |_| {
const result = @call(.auto, func, args);
_ = result;
}
const end = std.time.nanoTimestamp();
const elapsed_ns = @divTrunc(end - start, iterations);
return @intCast(elapsed_ns);
}
fn sumSlice(slice: []const u64) u64 {
var total: u64 = 0;
for (slice) |val| {
total += val;
}
return total;
}
test "benchmark sumSlice" {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const data = try allocator.alloc(u64, 1_000_000);
defer allocator.free(data);
for (data, 0..) |*item, i| {
item.* = i;
}
const ns_per_iter = try benchmark(allocator, sumSlice, .{data}, 1000);
std.debug.print("sumSlice: {} ns/iter\n", .{ns_per_iter});
}
十三、Zig 在生产环境中的应用
13.1 TigerBeetle:金融级分布式数据库
TigerBeetle 是用 Zig 编写的金融级分布式数据库,处理真实世界的金融交易。它的设计哲学与 Zig 完美契合:
- 零依赖:整个项目只依赖 Zig 标准库
- 确定性测试:利用 Zig 的无隐藏分配特性,实现确定性模拟测试
- 内存安全:手动内存管理 + GPA 检测,在金融场景下确保零内存泄漏
- comptime 驱动:大量使用 comptime 生成序列化/反序列化代码
TigerBeetle 团队曾公开表示:Zig 的显式设计是他们选择 Zig 的关键原因。
13.2 Bun:JavaScript 运行时的性能新标杆
Bun 是 Zig 生态最成功的项目。它证明了 Zig 在高性能运行时领域的可行性:
- 启动速度:比 Node.js 快 4 倍以上
- 包管理:bun install 比 npm install 快 30 倍
- 测试运行:bun test 比 jest 快 10 倍以上
- HTTP 服务器:吞吐量比 Node.js 高 3-5 倍
Bun 的成功不是偶然——Zig 的零隐藏分配和 comptime 泛型让 Bun 能够在关键路径上避免不必要的开销。
十四、Zig 的局限与挑战
客观地看,Zig 也有明显的不足:
14.1 生态仍然年轻
相比 C/C++ 和 Rust,Zig 的第三方库仍然很少。很多领域(如 GUI、图像处理、机器学习)几乎找不到成熟的 Zig 库。
14.2 还没有 1.0
Zig 目前是 0.14,语言规范仍在变化。这意味着升级版本时可能需要修改代码。
14.3 异步模型不确定
Zig 的 async/await 机制经历了一次重大重构,目前的标准库异步支持还在完善中。
14.4 学习资源少
相比 Rust 的丰富文档和教程,Zig 的学习资源仍然有限,尤其是中文资料。
十五、总结与展望
Zig 是一种独特的语言。它不追求安全性证明(Rust 的路),不追求表达能力极限(C++ 的路),而是追求一个简单但强大的目标:让程序员对代码有完全的控制。
在 AI 代码生成工具大行其道的 2026 年,Zig 选择禁止 AI 代码贡献,看似逆行,实则坚守了系统编程的核心价值:每一行代码都必须被人类理解。这不是对 AI 的恐惧,而是对系统软件可靠性的尊重。
Zig 的核心优势总结:
| 优势 | 说明 |
|---|---|
| comptime | 编译期计算的终极形态,比宏安全、比模板直观 |
| 无隐藏分配 | 每次内存分配都显式可见,可预测、可调试 |
| C 互操作 | 直接 import C,零成本调用,无需绑定代码 |
| 交叉编译 | 开箱即用,一个命令多平台构建 |
| 构建系统 | 内置 zig build,告别 CMake 痛苦 |
| 错误处理 | 显式错误集,无异常,控制流清晰 |
对于以下场景,Zig 值得认真考虑:
- 需要直接控制硬件的嵌入式开发
- 对性能和延迟有极致要求的基础设施
- 需要与大量 C 代码交互的项目
- 厌倦了 C++ 复杂性的系统程序员
- 想要一种"小而美"语言的开发者
Zig 可能不会取代 Rust 或 C++,但它为系统编程提供了一个新的选择——一个更简单、更透明、更可控的选择。在 AI 越来越多地参与代码编写的时代,这种选择的意义可能比我们想象的更大。
参考资源:
- Zig 官方文档:https://ziglang.org/documentation/
- Zig 学习指南:https://ziglearn.org/
- Bun 源码:https://github.com/oven-sh/bun
- TigerBeetle 源码:https://github.com/tigerbeetle/tigerbeetle
- Zig 社区 Discord:https://discord.gg/zig