我们是如何进行 Rust 到 Zig 重写的
一篇关于将 Roc 语言编译器从 Rust 重写到 Zig 的长文,引发了对系统语言中安全性、性能与工具链权衡的更广泛审视。评论者对比了 Rust 强大的静态保证和成熟生态,与 Zig 极快的增量构建、细粒度内存控制以及 1.0 前的不稳定性,并争论给 Zig 增加类似 Rust 的借用检查是否可行。讨论还深入到编译器和运行时究竟能在多大程度上提供“内存安全”,Go 等语言中的垃圾回收与调度器角色,以及在何种情况下为了性能或易用性而接受更多 unsafe 代码是合理的。
用于编译器实现的 Rust 与 Zig 对比
- 许多人认为,Zig 的增量构建(例如约 35 ms 的重建)是编译器工作的主要吸引力;Rust 被认为更慢,但在变快,并且有官方路线图以加快构建速度。
- 有人指出,在当前的 Roc 编译器中,完整构建在 Zig 里仍可能比 Rust 更慢;也有人强调,Zig 的架构是为未来性能优化的。
- 几位参与者认为,语言选择不如算法和数据结构重要;但也有人反驳说,一旦算法固定,底层内存/布局控制可以带来数量级的收益。
内存安全、unsafe 与借用检查
- 关于是否可以通过静态分析或 IR 工具为 Zig 添加类似 Rust 的借用检查器,争论非常激烈:
- 一方认为:如果没有带生命周期感知的语言设计、trait、封装以及受限的表达能力,这几乎是“不可能的”或极其不符合人体工学。
- 另一方则引用工具、自定义分析器以及 Ada/SPARK、类似 Oxide 的项目作为证据,认为可以“外挂”更多安全性,只是会付出成本并产生误报。
- 讨论的根本限制在于:别名分析和时间安全分析在一般情况下是不可判定的;Rust 通过限制表达能力(仿射/线性所有权)来解决这一点。
- Zig 的 ReleaseSafe 模式和调试分配器提供边界检查、泄漏检测、双重释放/部分 UaF 检测(利用不复用地址),但并不提供完整的时间安全性。
- 许多人强调,Rust 里的“内存安全”是一个特定且有限的保证;即使是安全 Rust,也可能由于编译器 bug 而错误编译或变得不安全(例如理论上的 CVE)。
“安全”是什么意思,以及编译器在其中的位置
- 有一段很长的分支讨论区分了:
- 内存安全(客观、可形式化)。
- 更广义的“安全”(取决于上下文:安全性、正确性、人身安全)。
- 有人认为安全是系统属性,而不是语言属性;一个安全的编译器也仍然可能产出有漏洞的二进制。
- 也有人反驳说,组件级保证仍然很有价值:减少 unsafe 面积能让调试、沙箱隔离和信任边界更可控。
- 还讨论了编译器是否属于“安全敏感”软件:
- 一种观点认为:编译器并不是为恶意输入而硬化的(例如 LLVM 明确的威胁模型);编译器中的 UB 只是“另一个 bug”。
- 相反的观点认为:编译器是关键信任根;其中的内存漏洞可能把代码注入到所有下游二进制中。
Go 运行时与调度
- 一位评论者声称 Go 的调度器是“世界上最复杂的”,并且通过以内存换并发,可以在吞吐上超过 Rust。
- 多条回复认为这一说法夸张,且与实际经验和基准不符,并指出很多高性能系统最后还是要手动优化内存。
- 还有人提到其他运行时(JVM、CLR、Erlang),并指出调度理论本身就很深;整体上大家普遍把该说法视为缺乏证据。
构建时间、缓存与工具链
- Rust 构建慢和制品目录很大是反复出现的抱怨;一些项目由于大量泛型和宏/代码生成,增量构建会持续数分钟(例如某些 GraphQL 技术栈)。
- 建议包括:
- 使用共享/全局 target 目录以及 sccache 等工具。
- Cargo 团队正在重新设计制品布局,以便实现垃圾回收和更好的缓存管理。
- Zig 团队解释说,对于微小编辑,增量重建的成本主要由依赖图遍历和变更检测决定,而不是代码生成,因此不同架构之间的性能应该相近。
Zig 的成熟度、破坏性变更与“可用于生产”
- 对 Zig 的 1.0 前状态存在张力:
- 支持者:它在实践中“可以用于生产”;1.0 前标签主要是为了保留频繁破坏性变更的自由。有人举出成功的生产用户作为例子。
- 批评者:核心 API 的频繁破坏性变更(例如 I/O API)使它不适合大多数生产团队;他们主张应采用正式的 semver 或 edition 方案,而不是无限制破坏。
- 有些人更喜欢 Zig 的做法(坦诚的波动性)而不是保守、不断累积包袱的语言;另一些人则坚持,严肃部署需要长期稳定性。
语言选择、GC 与性能
- 关于用于编译器的 OCaml 和其他托管/FP 语言的讨论:历史上已经有很成功的案例,存在非常快的编译器;有些人认为 Roc 的“必须是系统语言”这一假设过于强烈。
- 反方观点:现代 CPU 和语言特性(例如更复杂的闭包分配)改变了约束;对布局和分配进行细粒度控制可能非常重要。
- 更广泛的 GC 争论:
- 一些人认为反 GC 的情绪被夸大了,现实中的大多数服务都能接受现代 GC。
- 另一些人描述了高吞吐/低延迟系统,其中微秒级停顿都很重要,而 GC 暂停(即使是“低延迟”的)也不可接受,因此不能用 GC。
对 Roc 语言的反应与开放问题
- 几位评论者觉得 Roc 很有意思,但不确定它瞄准的细分领域和用途是什么(脚本、插件,还是服务器/客户端应用语言;它与 WASM、Gleam、Elm 的竞争关系如何)。
- 有人喜欢 Roc 的模式匹配和零分配字符串模式,但也指出路由示例里有一个微妙 bug,并担心在嵌入斜杠时会出现棘手语义。
- 还有一些轻微的风格反馈:对某些人来说,单独的类型注解行比 F# 风格语法更别扭。
文化、重写,以及 AI/Bun 的侧线讨论
- 有人觉得“把 Rust 重写成 X”的噪音似乎正在形成一波潮流,并提醒不要陷入语言部落主义;另一些人则强调“合适的工具做合适的事”,并接受在领域匹配发生变化时进行重写。
- 对另一个项目的 Zig 到 Rust 重写的简短比较引出了关于“UNO 反转”的玩笑,但也提出了对 1.0 前生态长期可持续性的疑问。
- 还有一条讨论问,为什么一家大型 AI 公司收购了一个 JavaScript 运行时厂商,而不是直接移植;回答集中在创业公司失败风险、战略控制和 acquihire 动机上。