Hacker News 中文摘要

RSS订阅

从 Rust 转投 Zig 是种什么体验 -- What Zig felt like, coming from Rust

过去7年,作者主要作为 Rust 开发者参与开源项目,对语言生态颇有感觉,偏爱函数式风格。始终好奇其他语言,Zig 作为候选 C 替代品已关注多时:更低层、轻量,渐获重视。早年用过 C,认为比较会很有趣。不过作者 Zig 经验始于当前项目,部分观察对日常使用者显得幼稚,决定重实现此前用 Rust 写过的某个不大不小的东西以作公平比较。

正文

引言

我做了 7 年 Rust 开发者,主要搞开源,喜欢函数式风格如干净函数和表现类型。一直好奇其他语言,Zig 作为候选 C 继任者在我雷达上很久:更低层、轻量、渐被严肃对待。早年用过 C,比较起来有趣。

先说前提:我的 Zig 经验始于本项目。有些观察对日常 Zig 用户显幼稚,决定受 Rust 习惯而非 Zig 惯用法影响。没关系,总要起步。

为公平比较,我重写了已用 Rust 写过的东西:非玩具不庞大,社区可用。选了 JSONPath(RFC 9535 的 JSON 查询语言)。Rust 版已有 jsonpath-rust,目标在 Zig 重做:zig-jsonpath。

IDE 支持

首先意外的是 IDE 支持近乎缺失。我用 RustRover 等 JetBrains,Zig 只给语法高亮和基本补全。迫使回命令行,反而成有趣体验:忘了裸 CLI 多直接。

第一课是 build.zig,轻松处理。我最终设定: - zig build test:跑所有测试 - zig build test -Dfilter="filter match function basic":跑单个测试 - zig build test -Ddebug-query=true:带调试跑所有 - zig build compliance:合规套件 - zig build check:单元+合规

接受后工作耳目一新。Zig 间接促使我从全 IDE 转向 helix+alacritty+zellij 设置。

扁平结构

Rust 等语言我常平衡文件大小和文件夹深度。Zig 允许嵌套但不鼓励(像 C),嵌套带导入摩擦。把相关放一文件分节导航更好。Zig 推扁平,需配套就建 model_<companion> 放旁边。

不认为适大项目,但阈值比预期高。Rust 早用文件夹,Zig 我推迟,最终没需。

这让我反思他语言中是否真需分文件还是习惯。也衡量项目大小:第一天忍不住建文件夹,可能比感觉小。

Rust 的 src 分散于 parser 和 query 子目录十几个文件;Zig 的 src 仅 root.zig、parser.zig、model.zig、model_query.zig、query.zig 五个。

测试

暂不论 RFC9535 合规,只看语言。Rust 我用内联单元测试(同文件方便)和集成测试(独立 tests 文件夹例外)。

预期 Zig 类似:可同文件写测试。但扁平结构下,要么每模型建 test 文件要么内联,都乱。我选内联并在 build.zig 配置,之后干净。

总体 Rust 写测管理更易;Zig 额外摩擦来自手动内存管理而非测试设施。

没有函数式范式

Rust 虽命令式但重度用函数概念:零成本迭代器、ADT、模式匹配、monadic 类型、trait、闭包等。我偏好函数式,库也如此:组合子错误控制、Data 带 map/flat_map、纯不可变、迭代器组合子、宏、和类型。

知不能全带去 Zig,希望保核心。实践 Rust 靠不可变组合子,Zig 推原地变更和命令式。

接近点:和类型。Rust 用 trait+match 直接;Zig 用 @typeInfo 鸭式检查 method 存在。

递归两边都不错:Rust 用 flat_map 递归后代;Zig 用递归收集后代。

核心差异:变更 vs 不可变 monad。Rust 的 flat_map 返回新 Data;Zig 在 while 中覆盖 cursors 或 remove。

Reduce vs Fork:Rust 用 map+reduce;Zig 用 fork 深拷贝状态后丢弃。

组合子 vs 循环:Rust 用 iter 链;Zig 用 while 手动索引。

主观:Zig 代码不如 Rust 可读。

分配器

分配器无处不在:几乎每函数接一个,每结构持一个。显式,接受后易跟。实践繁琐:严守 init/deinit,栈长易错。比 C 好但来自 Rust 得手动强制。

TestAllocator 救助:需写失败路径测试才可靠。代码复杂后 bug 缠结。

对比 Rust 举四例:忘 deinit 时 Zig 漏内存被 MemoryLeakDetected 抓,Rust 有 Drop 自动;错误路径跳 deinit 时 Zig 需 errdefer,Rust Drop 无条件;双重 deinit 时 Zig 跨函数双释放,Rust move 后绑定失效无法编译再 drop;移入结构失败孤儿分配时 Zig 需 errdefer free,Rust Vec::push 无此间隙。

库与核心 API

生态年轻。库少,正则 mvzr 不支持 \p{},实现 RFC9535 过滤函数时暴露。标准库 API 版本间变。不意外但记一笔。

总体印象

不同于 Rust 但印象好。直白、现代、极快,有潜力成真 C 继任者。仍年轻:语言形状未完,成熟后或加语法糖。

我愿继续贡献生态。

评论

讨论的分歧主轴有两处:一边是 Zig 能否成为 C 的「真正继承者」,多数人对此持保留态度,认为它只是更好写的 C,少数人则看好其直白、现代与速度;另一边是这篇带个人体验的文章由 LLM 润色是否合适,相当一部分人对行文里的 AI 腔调表示反感。

用 LLM 修饰个人体验类文章读起来令人反感

  • 作者虽在文末声明只让 AI 做了文字风格处理,但整天在职场里被这类文字包围的人已经本能排斥这种腔调(较多人) > 看这种文字看多了,脑子现在会自动抗拒(@diek)
  • 主题是纯粹的个人主观体验,本来就只有作者本人能表达,交给 LLM 生成没有意义(少数人)

认为 Zig 有成为 C 真正继承者的潜力

  • 语言直白、现代、速度极快,但明显还年轻:语言形态本身在若干地方显得未定型,随着成熟应该会补上更多顺手的语法糖与便利特性(少数人) > 语言还年轻,成熟后大概会吸收更多改善体验的特性与语法糖(@gigatexal)

认为 Zig 只是更好写的 C,把 C 的老问题一并继承

  • Rust 已在编译期、不用 GC 的前提下基本解决了内存管理,最大代价只是编译慢;对比内存泄漏、双重释放、内存破坏,宁可多等几分钟链接(较多人) > 宁可每次多花几分钟做最终链接,也不想要另一种选择(@plqbfbv)
  • 原文作者本人也承认,失去函数式范式是倒退,缺少零成本迭代器、惰性求值、模式匹配、单子式类型等一整套概念(少数人)

所谓「可变与不可变单子是核心差异」站不住脚

  • 原文那一节讲的只是「给函数和数据,裸数据就施加函数,容器就逐项施加」,这在 Zig 里用不可变数据结构完全可以做到,只需把分配器一并传入;Zig 版本出现可变,是程序员的选择而非语言强加,而且这件事和单子没有关系(少数人) > 是否使用可变数据是程序员的选择,不是语言强加的限制(@csense)

不该指望 C 有继承者,真正的问题在于 C 被用错地方

  • C 就是「高级汇编」:没有指针检查、危险的强制转换、没有边界检查,是设计使然而非疏漏;它是给操作系统和底层代码用的,写应用该用别的语言。Zig 更现代,但任何多一点手把手保护、像护栏的东西就不合格(少数人) > 想要写应用,就用 Pascal、Java、C#、Swift 或 Go(@hn_submit)

分配器崇拜被高估了

  • 从 Zig 到 Odin、C3、Jai,这些「C 继承者」语言都有这种执念;逐帧 arena 之类技巧在玩具问题上能带来巨大性能收益,但现实软件大多没那么简单,它只是有经验开发者工具箱里上千件工具之一,不值得占据头条(较多人) > 这类特性不是没用,但只该是工具箱里的一件,不配当头条(@tialaramex)
  • 有评论补充了 arena 的典型写法:在函数开头初始化,用 defer 在退出时统一释放(少数人)

工具链与编译期的对比被简化了

  • Zig 与 Rust 的工具链都值得称赞,但实务视角下 Rust 明显领先,Zig 更年轻,这不算意外;编译期方面 Rust 的野心是「无论代码何时运行结果都必须一致」,难度更大,与 Zig 的 comptime 本质上不可直接比较,因此对 Zig comptime 的赞誉和对 Rust 的贬低并不公平(少数人) > 把编译期结果与运行时机解耦是很有用的性质,但也让任务难得多(@weinzierl)

稳定性让 Zig 暂时当不了归档目标

  • 有人正在做一条包含 C 及 Go、Zig 等候选后继者的语言比较项目,其中一个用途是把 1980 年代的 32 位 K&R C 计算机代数系统归档移植。Zig 是很好的调试编译器,但还不够稳定,不适合作为归档目标(少数人)

对编程语言本身的热情正在消退

  • 怀念 LLM 之前的年代,那时读编程语言的讨论是享受;如今感觉一切都没那么有意义,语言专业知识仍有用途,但不足以让人对新的概念与想法兴奋起来(少数人) > 现在这一切都显得没什么意义,像是在背心算的规则(@karmakurtisaani)

有价值的补充

  • 原文把「Zig 几乎没有 IDE 支持」当成意外发现,但有经验的人完全预料得到这一点。
  • 有人用点菜类比选语言:在语言不通的餐厅看到同一招牌菜的三档套餐,选中间那档;Go 和 C23 都算有名门血统,而拿到 C 这个名字的那个,也一并继承了它的缺陷。
  • 有评论给出了一份 Zig、Rust 与 Go 的详细对比材料,作为进一步的阅读线索。