前言:为什么选择 Zig?

最近偶然发现了 Nullclaw 这个项目——一个用 Zig 编写的轻量级工具。令我惊讶的是,它在保持出色性能的同时,二进制体积也非常小巧。这让我对 Zig 这门语言产生了浓厚的兴趣,决定深入探索一番。

Zig 是一门现代化的系统级编程语言,由 Andrew Kelley 于 2016 年创建。它的设计目标是成为 C 的更好替代品,主打简洁、健壮和可维护性。与 C++ 或 Rust 相比,Zig 的学习曲线更加平缓,同时依然提供了强大的底层控制能力。


Zig 的设计哲学:Less is More

Zig 的核心理念可以用一句话概括:“专注于调试你的应用程序,而不是调试你的编程语言知识”

简化而非复杂化

许多现代语言通过不断增加新特性来变得"更现代",但 Zig 选择了一条不同的道路——通过简化来改进。Zig 的许多核心改进实际上是移除 C 和 C++ 中令人困扰的特性,而不是添加更多功能。

这种"少即是多"(Less is More)的哲学让 Zig 具有以下特点:

特性 C/C++ Zig
预处理器宏 ✅ 有(容易混淆) ❌ 无
隐藏控制流 ✅ 有(难以追踪) ❌ 无
隐藏内存分配 ✅ 有(标准库函数) ❌ 无
代码即所见 ❌ 宏会改变代码 ✅ 代码就是编译的代码

没有宏的清晰代码

C 语言的预处理器宏是一个常见的混乱来源。宏本质上是嵌入在 C 中的"第二语言",它会遮蔽你的实际代码——你不再 100% 确定哪些代码片段会被发送到编译器。

Zig 没有宏。你在 Zig 中编写的代码,就是实际被编译器编译的代码。这种透明性让代码更易读、更易调试。

无隐藏控制流

Zig 承诺没有隐藏的控制流。这意味着:

  • 没有意外的构造函数/析构函数调用
  • 没有运算符重载导致的意外行为
  • 没有隐式类型转换

每一行代码的行为都是明确和可预测的。


快速开始

安装 Zig

Zig 支持 Windows、macOS 和 Linux 三大平台。安装方式非常简单:

Windows 用户可以通过包管理器一键安装:

1
2
3
4
5
# 使用 winget
winget install zig.zig

# 或使用 Chocolatey
choco install zig

macOS/Linux 用户

1
2
3
4
5
# macOS (Homebrew)
brew install zig

# 或下载预编译二进制文件
# 访问 https://ziglang.org/download/ 获取最新版本

更多安装选项请参考官方文档

第一个 Hello World 程序

安装完成后,让我们创建第一个 Zig 项目:

1
2
3
mkdir hello-world
cd hello-world
zig init

这条命令会生成一个标准的项目结构。接着运行:

1
zig build run

你会看到标志性的输出:

1
2
All your codebase are belong to us.
Run `zig build test` to run the tests.

恭喜!你的第一个 Zig 程序已经成功运行了 🎉

生成的项目结构如下:

1
2
3
4
5
6
7
8
9
.
├── build.zig # 构建脚本(用 Zig 语言编写)
├── build.zig.zon # 项目依赖管理文件
├── src
│ ├── main.zig # 可执行程序入口(包含 main 函数)
│ └── root.zig # 库代码根模块
└── zig-out
└── bin
└── hello_world.exe

项目文件详解

  • main.zig:可执行程序的入口文件,必须包含 main() 函数
  • root.zig:库项目的根模块,如果是开发库而非可执行程序,通常从这里开始
  • build.zig:用 Zig 语言编写的构建脚本,执行 zig build 时会运行此文件
  • build.zig.zon:Zig 的包管理文件,用于声明项目依赖

学习资源推荐

Zig 社区提供了丰富的学习材料,以下是我精选的资源:

资源 类型 适合人群
Zig 官网 官方文档 所有人
Zig Book 在线书籍 初学者
Zig Guide 交互式教程 初学者
Ziglings 练习项目 动手实践者

特别推荐 Ziglings —— 这是一个类似 Rustlings 的交互式学习项目,通过修复一系列"故意写错"的程序来学习 Zig 语法。

开始使用 Ziglings

1
2
3
git clone https://codeberg.org/ziglings/exercises.git ziglings
cd ziglings
zig build

⚠️ 注意:Ziglings 需要最新版本的 Zig(开发版),而不是 stable 版本。


实战:Ziglings Exercise 001

让我们通过第一个练习来感受 Zig 的独特之处。

初次编译

运行 zig build 后,你会看到这样的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
> zig build
_ _ _
___(_) __ _| (_)_ __ __ _ ___
|_ | |/ _' | | | '_ \ / _' / __|
/ /| | (_| | | | | | | (_| \__ \
/___|_|\__, |_|_|_| |_|\__, |___/
|___/ |___/

"Look out! Broken programs below!"

Compiling: 001_hello.zig
error: 1 compilation errors
C:\tools\zig-0.16.0\lib\std\start.zig:676:43: error: 'main' is not marked 'pub'
const fn_info = @typeInfo(@TypeOf(root.main)).@"fn";
~~~~^~~~~
exercises\001_hello.zig:19:1: note: declared here
fn main() void {
^~~~~~~~~~~~~~

Ziglings hint: DON'T PANIC!
Read the compiler messages above. (Something about 'main'?)
Edit exercises/001_hello.zig and run 'zig build' again.

错误分析

错误信息的核心是这一行:

1
error: 'main' is not marked 'pub'

发生了什么?

在 C 或 Java 中,main 函数默认是全局可见的。但在 Zig 中,所有声明默认都是私有的(private)。这意味着如果没有显式标记为 pub(public),其他文件甚至编译器的启动代码都无法访问它。

当你运行 zig build 时,Zig 的启动代码(位于 std/start.zig)需要调用你的 main 函数作为程序入口。但由于 main 是私有的,启动代码"看不到"它,于是编译器报错。

修复方法

打开 exercises/001_hello.zig,找到:

1
fn main() void {

改为:

1
pub fn main() void {

就这么简单!添加 pub 关键字后,函数变为公开可见,编译就能通过了。

这个练习教会了我们什么?

这个看似简单的错误其实蕴含了 Zig 的两个核心设计理念:

1. 显式可见性控制

Zig 遵循"默认私有,显式公开"的原则:

1
2
3
4
5
// 私有函数 - 只能在当前文件内访问
fn privateFunction() void {}

// 公开函数 - 可以被其他模块访问
pub fn publicFunction() void {}

这种设计强制开发者思考"这个 API 是否应该对外暴露",有助于构建更清晰的模块边界。

2. 编译时反射(Comptime)

仔细看错误信息的第一行:

1
const fn_info = @typeInfo(@TypeOf(root.main)).@"fn";

这里使用了 @typeInfo@TypeOf —— 这是 Zig 的编译时反射特性。编译器在编译阶段就能检查类型信息,而不是等到运行时才暴露问题。

这种"编译时编程"(Comptime)是 Zig 最强大的特性之一,它让 Zig 能够在保持简洁的同时实现零成本抽象。

调试小贴士

当你看到 referenced by: comptime: ... 这样的报错时,通常意味着:

  • 🔍 编译器正在尝试"读取"你的代码结构
  • ⚠️ 某些类型定义、函数签名或可见性不符合规范
  • 💡 问题可以在编译阶段就被发现和修复

练习文件全貌

以下是第一个练习的完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//
// Oh no, this is supposed to print "Hello world!" but it needs
// your help.
//
// Zig functions are private by default, but the main() function
// must be public.
//
// A function is made public with the "pub" statement like so:
//
// pub fn foo() void {
// ...
// }
//
// Perhaps knowing this will help solve the errors we're getting
// with this little program?
//
const std = @import("std");

fn main() void {
std.debug.print("Hello world!\n", .{});
}

Ziglings 的每个练习都配有详细的注释说明,引导你发现并修复问题。这种"边做边学"的方式非常适合掌握 Zig 的编程思维。


下一步

接下来我计划:

  1. 📚 系统学习 Zig Book 的理论知识
  2. 🏃 完成 Ziglings 的所有练习,巩固语法基础
  3. 🛠️ 尝试用 Zig 写一些小工具,深入理解其内存管理和错误处理机制

Zig 作为一门年轻但设计精良的语言,正在吸引越来越多的开发者关注。如果你对系统编程感兴趣,不妨也加入 Zig 的学习之旅!


Zig 的核心特性概览

除了前面提到的设计哲学,Zig 还有几个值得关注的特性:

1. 编译时编程(Comptime)

Zig 的 comptime 关键字允许在编译时执行代码,这是实现零成本抽象的关键。与 C++ 的模板或 Rust 的宏不同,Zig 的编译时编程使用与普通代码相同的语法:

1
2
3
4
5
6
7
// 编译时计算斐波那契数
fn fibonacci(comptime n: u32) u32 {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}

const result = fibonacci(10); // 编译时计算,运行时常量

2. 显式错误处理

Zig 没有异常机制,而是使用错误联合类型(Error Union)来显式处理错误:

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

pub fn main() !void {
const file = std.fs.cwd().openFile("test.txt", .{}) catch |err| {
std.debug.print("Failed to open file: {}\n", .{err});
return err;
};
defer file.close();
// ...
}

3. 可选类型(Optional Types)

Zig 使用 ?T 语法表示可能为空的类型,强制开发者处理空值情况:

1
2
3
4
5
6
7
8
9
10
fn findUser(id: u32) ?User {
// 可能返回 null
}

const user = findUser(42);
if (user) |u| {
// 处理找到的用户
} else {
// 处理用户不存在的情况
}

4. 手动内存管理 + 安全抽象

Zig 不强制使用垃圾回收,而是提供显式的内存管理。同时,标准库提供了安全的抽象:

1
2
3
4
5
6
7
// 使用 ArenaAllocator 简化内存管理
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();

// 所有在此分配的内存会在 arena.deinit() 时一次性释放
const buffer = try allocator.alloc(u8, 1024);

5. 交叉编译开箱即用

Zig 的交叉编译能力非常强大,无需额外配置即可为目标平台编译:

1
2
3
4
5
# 编译为 Windows 可执行文件(在 macOS/Linux 上)
zig build -Dtarget=x86_64-windows

# 编译为 ARM64 Linux 可执行文件
zig build -Dtarget=aarch64-linux-gnu

谁适合学习 Zig?

根据 Zig Book 的建议,Zig 适合以下人群:

  • 有编程经验的开发者 —— 不需要底层语言经验,Python/JavaScript 背景也能快速上手
  • C/C++ 开发者 —— 想要更现代、更安全的工具,但不想忍受 Rust 的复杂性
  • 嵌入式开发者 —— 需要精细控制内存和性能
  • 追求简洁的程序员 —— 厌倦了 C++ 的复杂特性,想要"刚刚好"的工具集

总结

Zig 是一门简单但强大的系统编程语言。它不会用复杂的特性来炫耀,而是通过移除那些导致混乱和错误的机制来提供更好的开发体验。

正如 Zig 官方所说:

“Focus on debugging your application rather than debugging your programming language knowledge.”

(专注于调试你的应用程序,而不是调试你的编程语言知识。)

这正是 Zig 的魅力所在——它让你把精力集中在解决问题上,而不是与语言本身搏斗。


本文持续更新中,欢迎关注后续的学习笔记。