看到这篇 Devlog 时,我第一反应是:这帮人是真的“疯”。

别的语言都在想怎么讨好开发者,怎么补齐语法糖,Zig 团队却在做一件极其硬核、甚至有点“冒犯”操作系统厂商的事——

他们正在试图绕过 Windows 的常规 API,直接捅到底层内核。

Zig 0.16 版本,一场针对臃肿和低效的宣战。

代码里的“变脸”绝活

先说个最直观的改动。

image

Zig 现在允许你在不修改业务逻辑代码的情况下,像换积木一样切换整个程序的 I/O 模型。

这听起来很抽象?看代码就懂了。

你写了一个打印 "Hello, World!" 的函数 app,它完全不知道底层是怎么运作的。但在 main 函数里,你可以决定是用传统的多线程模式:

var threaded: std.Io.Threaded = .init(gpa, .{...});
const io = threaded.io();
return app(io);

或者,直接换成事件驱动模式,也就是基于 io_uring(Linux)或者 GCD(macOS)的高性能异步模型:

var evented: std.Io.Evented = undefined;
try evented.init(gpa, .{...});
const io = evented.io();
return app(io);

上面的 app 函数连一个标点符号都不用改。

如果你用 strace 去抓取系统调用,你会发现底层的翻天覆地:前者是老老实实的 writev,后者则是复杂的 io_uring_setup 和 io_uring_enter。

这玩意儿现在被称为 std.Io.Evented,基于用户态栈切换,也就是大家常说的“协程”。

虽然目前还被打着 Experimental(实验性) 的标签,甚至用这个模式跑编译器自己都会出现莫名其妙的性能下降,但不得不说,这架构设计得是真漂亮。

Windows 上的“叛逆者”

更有意思的是 Zig 对 Windows 的态度。

Andrew Kelley 在日志里毫不客气地指出了一个现状:Windows 的 API 层级太臃肿了。

很多开发者都在用 kernel32.dll,觉得这就够底层了。

但 Zig 团队发现,这些高层 API 经常会引入不必要的堆分配、额外的失败模式,甚至还有莫名其妙的 CPU 占用。

他们的解决方案简单粗暴:绕过 kernel32,直接调用 ntdll 里的原生接口。

举个获取随机数的例子。

以前大家(包括 Chromium、Firefox、Rust)都老老实实调 advapi32.dll 里的 SystemFunction036。但这玩意儿在 Windows 8 之后,第一次调用时会动态加载 bcryptprimitives.dll,还要跑一遍自检,甚至会因为堆分配失败而报错——尽管文档上说它“永远不会失败”。

Zig 怎么干?直接跳过这些花里胡哨的 DLL,通过 NtDeviceIoControlFile 直接去读设备 \Device\CNG。

再比如读写文件。

Windows 提供的 ReadFile 接口,返回值是个 BOOL,你得再调 GetLastError 才知道出了啥事。而底层的 NtReadFile 直接给你返回状态码,干脆利落。

个人觉得这种极客精神挺让人佩服的。为了极致的性能和可控性,他们宁愿去维护一套更底层、更复杂的绑定,也不愿意在系统提供的舒适区里躺平。

正在消失的 C 代码

除了折腾 I/O,Zig 还在干另一件“得罪人”的事:删除 C 代码。

这就是 zig libc 计划。

他们不再把 libc 当作必须引入的外部依赖,而是正在用 Zig 代码一点点重写这些 C 函数。像 memcpy、atan2 这种基础函数,现在都是 Zig 标准库里的直接实现。

数据不会骗人:目前大约已经有 250 个 C 源文件被彻底删除了。

这有什么好处?

好处太大了。Zig 对编译过程有了完全的控制权,不再受制于第三方的 libc 项目。这意味着更快的编译速度、更小的安装包,以及——听好了——更激进的优化。

因为 libc 现在和你的代码在同一个编译单元里,编译器可以在 libc 和你的代码之间进行跨边界优化。这就像 Link-Time Optimization(LTO),但是在编译前端就完成了,效率更高。

包管理的“P2P”野望

最后聊聊两个让开发者生活质量直线提升的小改动。

一个是依赖管理。

以前 Zig 的包都在缓存里,现在它们默认被存到项目本地的 zig-pkg 目录下。你可以随意编辑这些依赖,看看改改源码会发生什么,甚至把目录替换成你 git clone 下来的 fork 版本。

配合新加的 zig build --fork=[path] 参数,你可以瞬间把整个依赖树里的某个库替换成你本地的修改版。

这对于修复上游 Bug 或者调试依赖地狱简直是神器。修好了,你可以提交 PR;修不好,删掉参数,世界又清净了。

更有意思的是 Andrew 提到的一个未来计划:P2P 种子分发依赖。

既然全局缓存里的包都是压缩好的标准格式,为什么不让开发者之间直接互相分享呢?

想象一下,以后下载依赖可能不需要去中心服务器挤,而是直接从邻居那里“吸血”。这不仅能抗住网络故障,还能搞个“热门包排行榜”——看看哪个开源库的种子最多。

结语:技术之外

整篇文章看下来,你既能看到技术上的激进,也能看到工程上的务实。

有人可能会说:“Zig 都 2026 年了还没发 1.0,这项目是不是要凉?”

我在 Hacker News 的评论区里确实看到了不少类似的质疑。但也有人说得对,没人逼着你用 Zig,但也没人能否认他们正在尝试一些真正有趣的新东西。

image

Rust 在 io_uring 的安全抽象上还在苦苦挣扎,而 Zig 已经凭借其“手动管理一切”的哲学,把这套机制推进到了可用的阶段。

文章的最后,作者 Andrew Kelley 突然笔锋一转,写下了几句沉重的话。

就在他写这篇日志的时候,离他家不到五英里的地方,武装部队正在向和平抗议者发射催泪瓦斯。他说他希望下次能有勇气加入邻居的行列,而不是像个懦夫一样坐在家里写代码。

image

我们在屏幕前重构代码、优化内核、争论哪个语言更好,试图构建一个完美的逻辑世界。但窗外那个充满混乱、冲突和不公的现实世界,依然在轰隆作响。

代码能改变世界吗?

也许能,也许不能。但至少,Zig 试图让代码本身变得更纯粹一点。

这就够了。

参考链接:
https://ziglang.org/devlog/2026/#2026-02-13