首页 > 开源 > 深度使用 Zig 四个月:最爱的设计和最失望的坑,来自同一种偏执

深度使用 Zig 四个月:最爱的设计和最失望的坑,来自同一种偏执

OSChina资讯 2026-10-28 11:54 5 阅读 查看原文

Anna Liberty 放弃 Zig 后转用了几年 Rust,近日她表示自己大约四个月前重新开始使用 Zig,还攒了一篇挺有料的体验报告。有意思的地方在于:她最爱的几个特性和最失望的那件事,来自同一套设计哲学的两面。

先说不爽的。她第一个项目写 snurl(小网络协议库,Gemini、Finger、Gopher 那类),想按 TigerStyle 做测试和 fuzz,结果发现 zig init 生成的 main.zig 里演示的 fuzzer 功能其实还没做完——她上一篇博客还为 fuzzing 兴奋过,后来才发现踩空。考虑到 Zig 的状态不意外,但确实失望。另一个坑是 anyzig:她需要同时用 zig master 和 0.16.0,anyzig 解决了这个,但在没有 build.zig.zon 的目录下会失灵,导致单文件脚本的自动格式化用不了。

她喜欢的东西更值得说。显式 allocator 参数——每个 Zig 函数都要显式接收 allocator,跟大多数语言用全局默认或隐式上下文(她点了 Odin 的名)不一样。她的评价是:想让某块代码用 arena、另一块用通用分配器,或者只需要 FixedBufferAllocator,Zig 的风格让这一切一目了然,而且很难把错误的分​​配器传进去。她顺手对比了 Rust:Rust 的隐式分配是"不会失败"的,内存耗尽直接 panic;现在 Rust 在补显式分配,但那是往语言上外挂一层,不是从地基长出来的。

IO 参数是同一逻辑的延伸,而且她觉得更值。凡是要跟底层操作系统打交道的函数都得传一个 IO 参数,输入输出和上下文全从这里来。好处在测试上特别明显:塞一个测试用的 IO 实例进去,想怎么改输入流、想让写入失败都行。她还补了一句哲学层面的收益——传 IO 参数让"这个程序是不是纯的"一眼可辨。

依赖文化是她另一个大爱。核心信条就一个词:避免。不需要就别加。真需要的时候,通常是经过检验的库,用 translate-c 就能无缝接入,也可以把源码 vendor 进来自己审。她自己的 Zig 项目一般只有一两个直接依赖、零间接依赖;同样的项目在 Rust 里,最小的也有几个直接依赖加几十个间接依赖。这既是文化差异,也因为反射、随机数、错误处理、JSON 解析这些在 Zig 里是语言或标准库自带的——不用每个项目都依赖 serde 和 syn。

错误处理她也站 Zig。最偷懒的写法就是 try 加个 !,但至少不会像 Rust 那样在原型阶段 panic 一下、然后一直留在生产代码里。她见过 Rust 生产代码用 panic 而不是返回错误,而 Rust 要想优雅点就得 Result<type, box<dyn std::error::error>> 这种一长串,或者引个 anyhow——为合理的错误处理再加一个依赖。

增量编译是压轴好评。zig build --watch -fincremental 会盯着改动、只重编你动过的部分、一直优化到链接,快到"低于人类感知阈值"。她的工作流是编译器开在编辑器旁边,保存就更新,没有分心的时间窗口。对比 Rust:小项目增量循环 10 秒以上很常见,"够长到让你分心,又不够长到能做别的事"。她认为这是 Rust 的先天劣势——为了保持向后兼容,它不敢为了编译速度大改。而 Zig 维护者愿意为了更好的结果破坏任何东西。

代价当然也在:增量编译目前只支持 Linux 和 macOS 的 x86_64,其它平台架构还用不上。

参考来源