当 Bun 用 AI 亲手换掉自己的"心脏":从 Zig 到 Rust 的 11 天大迁徙,揭示了软件工程的哪些新真相?
引言:一场"自杀式"重写,一个时代的隐喻
2026年5月,编程界上演了一出荒诞又深刻的戏码。
Bun——这个以 Zig 语言构建、号称比 Node.js 快数倍的 JavaScript/TypeScript 全栈运行时——在被它自己的用户 Claude Code(Anthropic 的 AI 编程工具)因内存泄漏问题拖垮后,决定亲手把自己从 Zig 重写成 Rust。
整个过程仅用了 11 天,涉及 1448 个文件的机械翻译、近 100 万行新增代码、6755 次提交。测试套件达到 99.8% 通过率,最终直接合并进主分支。
PR #30412 的代码量太大,以至于直接把 GitHub 页面搞崩了。
这不是一个普通的技术八卦。这件事背后,藏着 2026 年软件工程领域最值得深思的几个命题:
- AI 辅助编程的规模化实践边界在哪里?
- 一门系统级语言(Zig)的工程化困境与 Rust 的不可替代性
- Anthropic 收购 Bun 背后的战略逻辑,以及这对 Claude Code 意味着什么
- 当 AI 能批量生产代码时,"代码所有权"和"代码质量"如何重新定义?
本文将从技术、工程、组织和行业四个维度,把这件事彻底拆透。
一、背景:为什么 Bun 会选择 Zig,又为什么最终"背叛"了它
1.1 Zig 的野心与陷阱
Bun 项目始于 2021 年,创始人 Jarred Sumner 选择 Zig 作为核心实现语言,这在当时是一个非常有争议但又极具吸引力的选择。
Zig 的核心设计哲学是"没有隐藏控制流、没有隐藏内存分配、没有宏"——它比 C 更透明,同时保持了与 C 几乎无缝的互操作性。对于一个 JavaScript 运行时来说,这意味着:
- 零成本抽象:可以写出接近手写 C 的性能,同时保持代码可读性
- 精确的内存控制:运行时完全掌控何时分配、释放内存
- 编译速度极快:比 Rust 快一个数量级,开发迭代体验好
Jarred Sumner 曾在多个场合表示,Zig 是构建高性能 JavaScript 运行时的"完美语言"。从技术上看,这个判断没有错——Zig 版本的 Bun 在性能基准测试中确实表现优异,JavaScript 执行速度、HTTP 服务器吞吐量、包安装速度都大幅领先 Node.js。
然而,工程现实给理想主义上了一课。
Zig 是一门极其年轻且仍在快速迭代的语言。从 0.9 到 0.14,Zig 经历了多次破坏性变更,每一次编译器升级都可能让既有代码无法编译。更关键的是,Zig 的工具链和生态远未成熟——没有像 Cargo 那样可靠的包管理器,没有稳定的语言服务器,调试工具链相当原始。
当项目规模从几万行扩展到接近百万行时,这些问题被急剧放大。
1.2 内存泄漏:埋进地基的定时炸弹
对于一个 JavaScript 运行时来说,内存管理的正确性是生命线。每天处理数十亿次请求的运行时,任何内存泄漏都会以指数级放大。
然而,Zig 虽然提供了精确的内存控制能力,却没有编译器层面的强制保障。手动内存管理的每一步都需要开发者自己保证正确性。随着代码规模扩大,人工审查的难度呈几何级增长,而 Bun 的内存泄漏问题在生产环境中频繁出现。
最讽刺的蝴蝶效应来了:
Anthropic 在 2025 年 12 月收购了 Bun。之后,Bun 深度嵌入了 Claude Code 的技术栈——Claude Code 内置了 Bun 运行时来执行 JavaScript/TypeScript 代码。
然后:Claude Code 频繁因 Bun 的内存泄漏而崩溃。
一个被自己的内存泄漏问题坑惨的 AI 工具,去重写那个有问题的工具——这件事的荒诞程度,大概连科幻小说都不敢这么写。
二、技术解析:一次"纯机械"的大迁徙是怎样完成的
2.1 为什么选择 Rust 而不是其他语言
在确定"必须重写"之后,Bun 团队面临一个技术选型问题:换成什么语言?
选项分析:
| 语言 | 优势 | 劣势 |
|---|---|---|
| Rust | 内存安全保证、优秀的工具链(Cargo)、活跃生态、编译时消除 dangling pointer/buffer overflow | 编译速度较慢、async 生态复杂 |
| Go | 简单、goroutine 并发模型成熟、编译快 | 运行时 GC 延迟、不够底层 |
| C++ | 极致性能、完全控制 | 内存安全完全依赖程序员、工具链原始 |
| Zig | 性能好、与 C 无缝互操作 | 语言不稳定、生态弱 |
最终选 Rust,核心原因只有一个:Rust 的编译器提供了"内存安全的强制保证"。
Rust 的所有权系统(Ownership)和借用检查器(Borrow Checker)能在编译时捕获 use-after-free、data race、buffer overflow 等常见内存安全漏洞。对于 Bun 这种基础设施级软件,这个特性是无价的。
值得注意的是,Jarred Sumner 明确表示:Bun 重写后依然不使用 async Rust。这说明团队对 Rust 的异步运行时复杂度有清醒的认识,选择了一条更保守但更可控的技术路径。
2.2 AI 翻译流水线:对抗工作流的工程实践
这次重写最令人震惊的不是结果,而是过程。
Jarred Sumner 事后透露,这次重写采用了"对抗工作流"(Adversarial Workflow):
"整个讨论有点反应过度了。300 多条评论,全都围绕一堆根本还跑不起来的代码。我们并没有决定一定要重写。而且这些代码最后被全部扔掉的概率其实非常高。我只是很好奇:一个真正可运行的版本到底会是什么样、用起来感觉如何、性能如何,以及让它通过 Bun 的测试套件并真正变得可维护,到底会有多难。"
具体分工如下:
┌─────────────────────────────────────────────────────────┐
│ AI 翻译流水线 │
├──────────────┬──────────────────────────────────────────┤
│ 翻译Agent │ 将 Zig 文件机械翻译为 Rust 草稿 │
│ 验证Agent │ 对照 Zig 代码和 Rust 规范做一致性验证 │
│ 修复Agent │ 处理类型不匹配、lifetime 报错 │
│ Audit Agent │ 审查所有 unsafe 代码块 │
│ Windows Agent │ 专门处理 Windows 平台的兼容性 bug │
└──────────────┴──────────────────────────────────────────┘
这个流水线的关键洞察是:它没有试图让 AI"理解"代码,而是让 AI 做一个高吞吐量的翻译机器。 代码的语义正确性由原有的 Zig 测试套件来保证,AI 的任务只是把 Zig 语法"变成" Rust 语法。
2.3 机械翻译的工程挑战:99.8% 通过率意味着什么
最终数字:
- 翻译文件数:1448 个 Zig 文件
- 提交数:6755 次
- 新增代码:约 96 万行
- 测试通过率:99.8%(原有测试套件)
- 耗时:11 天(另有说法是 6 天核心冲刺)
99.8% 的通过率听起来接近完美,但 Bun 团队和社区都清楚:测试通过率不等于代码质量等于原版。
一些开发者在社区中提出的核心质疑是:
"当 AI 生成代码的速度远远超过人类审查代码的速度时,我们该如何证明这些代码真的值得信任?"
这个问题没有简单的答案。测试套件能保证行为一致性(输出结果相同),但不能保证实现质量(没有隐藏 bug、没有性能退化、没有潜在的未定义行为)。
2.4 代码量"打爆 GitHub":一次 PR 的工程奇观
PR #30412 包含了超过 100 万行新增代码。这个量级直接导致 GitHub 的 diff 渲染页面无法正常加载——GitHub 的前端根本没有考虑过有人会提交如此规模的重写。
# PR 信息
PR: #30412
Title: [RFC] Rust rewrite of bun runtime
Files changed: 1448
Commits: 6755
Additions: ~960,000 lines
Deletions: ~920,000 lines (Zig code removed)
这个 PR 本身就是一个工程奇观,它让我们意识到:GitHub 作为一个代码托管平台,其前端交互设计隐含了"人类审查代码"的假设。当代码由 AI 批量生成时,这个假设不再成立。
三、工程哲学:为什么"保持架构不变"是这次重写最聪明的决定
3.1 不重写架构,只替换语言
很多大型重写失败的案例,问题不在于语言选择,而在于把重写当成了重新设计。团队在重写的过程中忍不住想要"修缮"既有的架构缺陷,最终导致两个系统并行演化,永远无法收敛。
Bun 的 Rust 重写采取了一个极其克制的策略:完全保留原有的架构设计、数据结构、模块边界。
- 相同的调度器设计:保留了原有的工作窃取调度器
- 相同的数据结构:JS 对象模型、字符串实现、V8 集成方式不变
- 相同的 FFI 策略:继续使用 Zig 的 C interop 模式(通过 cbindgen 风格的 Rust-C 绑定)
- 相同的第三方依赖策略:Bun 素来以"少用第三方库"著称,Rust 版本延续了这一理念
这意味着,这次重写本质上是一次编译器替换,而不是一次架构重构。这是一个非常重要的工程判断。
3.2 性能实测:Rust 版本真的更好吗?
根据 Bun 官方公布的基准测试数据:
| 基准项 | Zig 版本 | Rust 版本 | 差异 |
|---|---|---|---|
| HTTP 吞吐量 | 基准 | +2% ~ +8% | 持平或略好 |
| 冷启动时间 | 基准 | -3ms | 略快 |
| 二进制体积 | 基准 | -3 ~ -8 MB | 缩小 |
| 内存占用(长期运行) | 基准 | 显著降低 | 大幅改善 |
| Windows 兼容性 | 有 bug | 已修复 | 大幅改善 |
最关键的改进不是峰值性能,而是长期运行的内存稳定性——这正是这次重写的原始动机。Rust 编译器在编译期的内存安全检查,从根本上消除了那类需要运行很长时间才能触发的"慢速内存泄漏"。
3.3 二进制体积缩小:Rust 优化带来的意外红利
Rust 版本比 Zig 版本二进制体积小 3-8 MB,这是一个意外的收获。
分析其原因:
- Rust 的链接模型更高效:相比 Zig 的激进内联策略,Rust 的 LTO(Link Time Optimization)在链接阶段能更全局地做内联和死代码消除
- panic 处理更紧凑:Rust 的 panic 默认是 panic-on-abort(不展开栈),比 Zig 的默认展开更省空间
- 目标文件格式:ELF/Mach-O 中的调试信息压缩更好
// Rust 版本的 panic 策略(嵌入式友好)
// Cargo.toml
[profile.release]
panic = "abort" // 禁用栈展开,减小二进制体积
lto = true // 链接时优化
codegen-units = 1 // 最大优化
opt-level = "z" // 优化体积而非速度
strip = true // 发布时去掉调试符号
四、Anthropic 收购背后的战略棋局
4.1 为什么 Anthropic 要买一个 JavaScript 运行时?
2025 年 12 月,Anthropic 收购 Bun 的消息让很多人困惑:AI 公司为什么要买一个 JavaScript 运行时?
答案藏在 Claude Code 的技术栈里。
Claude Code 是一个 AI 编程助手,它需要:
- 快速执行用户提交的代码片段(沙箱执行)
- 处理 npm 包依赖(npm install 在 Node.js 上很慢)
- 运行 JavaScript/TypeScript 测试套件
Bun 在这些场景下有决定性优势:包安装速度是 npm 的 10 倍,HTTP 服务器性能比 Node.js 高数倍,冷启动时间接近零。
对于一个 AI 编程工具来说,每一次用户交互都可能触发一次代码执行,速度差异直接等同于用户体验差异。
Anthropic 的商业逻辑:
Claude Code(需要极速代码执行)
↓
Bun(极速 JavaScript 运行时)
↓
内存泄漏导致 Claude Code 频繁崩溃
↓
Anthropic 选择:买下 Bun,自己修复
↓
Claude AI + Claude Code + Bun = AI 原生开发工具链
4.2 Claude Code 内置 Bun 运行时:这对用户意味着什么
随着收购完成,Claude Code 已经开始在 beta 阶段内置 Bun 运行时。这意味着:
对开发者(用户)的好处:
- 代码执行速度更快
- 包安装几乎瞬间完成
- 依赖解析错误减少
对 Anthropic 的战略好处:
- 不再依赖外部维护者的节奏,可以自主控制关键依赖的稳定性
- 可以在 Bun 运行时中嵌入更多 Claude 特有的运行时优化
- 为未来的"Claude 原生"JavaScript 开发环境奠定基础
风险:
- AI 公司控制核心基础设施引发社区担忧
- Bun 开源项目的治理独立性受到影响
五、AI 编程的新范式:对抗工作流揭示的工程真相
5.1 AI 翻译的适用条件:什么项目可以做,什么不行
Bun 的案例给我们提供了一个非常清晰的判断框架:
AI 机械翻译适用于满足以下条件的项目:
- ✅ 有完整的测试套件:Bun 原有测试覆盖了 99.8% 的行为边界
- ✅ 有明确的规范:JavaScript 语义由 TC39 标准定义,Bun 只需实现正确行为
- ✅ 有可机器读取的接口契约:模块边界清晰,类型签名明确
- ✅ 目标语言与源语言有良好对应关系:Zig → Rust 的类型系统映射相对直接
- ✅ 项目规模足够大:人工重写成本极高,AI 的高吞吐量优势明显
不适用于:
- ❌ 需要理解业务逻辑的遗留代码(没有测试、语义模糊)
- ❌ 高度创新的项目(没有规范可循,需要真正的设计判断)
- ❌ 高度政治性的代码(涉及多方利益、没有唯一正确答案)
5.2 人类的角色:从"写代码"到"审代码"
Jarred Sumner 的另一句话值得玩味:
"未来开源可能禁止人类提交代码。"
这句话当然是一种夸张的修辞,但它指向了一个真实的趋势:在 AI 高效产出代码的时代,人类工程师的核心价值正在从"编写"转向"判断"。
具体来说:
| 传统模式 | AI 辅助模式 |
|---|---|
| 工程师写代码 | AI 生成代码候选 |
| 工程师 review 代码 | 工程师判断质量 |
| 工程师跑测试 | 测试套件自动验证 |
| 工程师设计架构 | 工程师定义架构约束,AI 填充实现 |
| 工程师 debug | AI + 工程师协同定位 |
这不是说人类被替代了,而是说人类从"执行层"上升到了"决策层"。这个转变要求工程师有更强的架构能力、更深的领域理解、更精准的判断力。
5.3 99.8% 通过率之后的 0.2%:AI 时代的测试哲学
测试套件 99.8% 的通过率,意味着还有 0.2% 的测试用例失败了——或者更准确地说,有 0.2% 的场景新代码的行为与原版不一致。
这 0.2% 可能是:
- 竞态条件:只在特定时序下出现的 bug,测试套件没有覆盖
- 边缘情况:输入超出正常范围的 corner case
- 平台差异:Windows 特定行为,Unix 测试覆盖不了
对于生产级软件来说,这 0.2% 可能是灾难性的。
这里引出了一个 AI 时代的核心工程问题:
测试套件的价值被重新定义。 在 AI 生成代码的场景下,测试套件不仅验证当前实现的正确性,还承担了验证 AI 翻译等价性的新使命。这意味着测试套件的覆盖率、边界 case 的设计、对罕见场景的覆盖,都变得比以往任何时候都更重要。
六、Bun 的未来:从"工具"到"平台"的蜕变
6.1 Rust 之后:性能优化进入深水区
Bun 团队已经明确表示:Rust 重写不是终点,而是新起点。Rust 版本还处于 canary 频道,优化工作仍在进行中。
下一步的优化方向:
- SIMD 加速:利用 Rust 的 SIMD intrinsics 加速字节码解释器
- Profile-Guided Optimization (PGO):基于真实运行数据做二次编译优化
- JIT 编译器改造:Zig 版本的 JIT 有很多历史包袱,Rust 版本有望重构出一个更干净的 JIT
6.2 Claude CoPilot:AI 原生开发工具链的雏形
Anthropic 收购 Bun 的真正野心,可能不只是为了让 Claude Code 不崩溃。
随着 Claude Code 深度集成 Bun 运行时,Anthropic 正在构建一个独特的价值主张:
Claude(推理能力)
+
Claude Code(Bun 执行环境)
+
Bun 运行时(极速 JavaScript/TypeScript)
=
AI 原生开发闭环
在这个闭环中,Claude 的推理、Claude Code 的执行、Bun 的运行时,三者被深度整合,AI 可以在运行时直接感知代码执行的性能数据,并以此优化推理结果。这是任何依赖外部 Node.js 运行时的竞品所无法复制的优势。
6.3 社区反应:开源世界的分裂与焦虑
Bun 宣布 Rust 重写后,Hacker News 和 GitHub 讨论区的反应呈现出明显的两极化:
支持者的观点:
- "Rust 的内存安全保证对基础设施软件来说是不可拒绝的"
- "测试套件 99.8% 通过率已经是极高的置信度"
- "Anthropic 背书意味着更多资源投入,Bun 的未来更光明"
质疑者的观点:
- "Anthropic 控制了 Bun,这改变了开源治理的本质"
- "AI 批量生成的代码真的可维护吗?未来还有谁能接手?"
- "99.8% 测试通过率不等于代码等价的 0.2% 可能是最难发现的隐藏 bug"
这些讨论的本质,其实是一个更大的问题:当 AI 成为代码生成的主要力量时,"开源软件"的含义是否需要被重新定义?
七、实战:用 Bun Rust 版本搭建你的第一个生产级 API
说了这么多理论,让我们来点实际的。Bun Rust 版本(canary 频道)已经开放测试,以下是上手指南:
7.1 安装 Bun Rust 版本(Rust 重写版)
# 通过 canary 频道安装(Rust 版本)
bun upgrade --canary
# 验证版本信息
bun --version
# 输出类似:1.4.0-canary.x (rust-rewrite)
# 确认是否使用了 Rust 运行时
bun --diagnostics
7.2 搭建一个高性能 HTTP API
// server.ts
// Bun Rust 版本的高性能 HTTP 服务器
const server = Bun.serve({
port: 3000,
tls: {
key: "./keys/key.pem",
cert: "./keys/cert.pem",
},
fetch(req) {
const url = new URL(req.url);
const pathname = url.pathname;
// 路由分发
switch (pathname) {
case "/api/users":
return handleUsers(req);
case "/api/posts":
return handlePosts(req);
case "/health":
return Response.json({ status: "ok", runtime: "bun-rust" });
default:
return new Response("Not Found", { status: 404 });
}
},
});
async function handleUsers(req: Request): Promise<Response> {
const db = await Bun.sql.open("sqlite:./data.db");
if (req.method === "GET") {
const users = await db.query<User[]>("SELECT * FROM users LIMIT 100");
return Response.json(users);
}
if (req.method === "POST") {
const body = await req.json<Partial<User>>();
const result = await db.query(
"INSERT INTO users (name, email) VALUES (?, ?) RETURNING *",
[body.name, body.email]
);
return Response.json(result[0], { status: 201 });
}
return new Response("Method Not Allowed", { status: 405 });
}
async function handlePosts(req: Request): Promise<Response> {
const db = await Bun.sql.open("sqlite:./data.db");
const posts = await db.query<Post[]>(`
SELECT p.*, u.name as author_name
FROM posts p
JOIN users u ON p.user_id = u.id
ORDER BY p.created_at DESC
LIMIT 50
`);
return Response.json(posts);
}
console.log(`Bun Rust 运行时监听端口 ${server.port}`);
7.3 基准测试:Rust 版本 vs Zig 版本
// benchmark.ts - 简单的吞吐量对比
import { bench, run } from "bun";
const server = Bun.serve({
port: 0, // 随机端口
fetch(req) {
return new Response("Hello from Bun " + (process.versions.bun ?? ""));
},
});
await bench({
name: "Simple HTTP Response",
iterations: 100_000,
runs: 5,
fn() {
// 使用内置 HTTP 客户端
fetch(`http://localhost:${server.port}/`).then(r => r.text());
},
});
server.stop();
await run();
预期结果(Bun 官方基准):
- Rust 版本在 HTTP 并发吞吐量上与 Zig 版本持平或略优
- 长期运行内存稳定性:Rust 版本明显更好(无内存泄漏)
- 冷启动时间:减少约 3ms
7.4 与 Node.js 的性能对比
# 启动基准测试服务器
bun run server.ts &
# 使用 autocannon 压测
npx autocannon -c 100 -d 10 http://localhost:3000/
# 对比 Node.js(相同代码)
# node server.js &
# npx autocannon -c 100 -d 10 http://localhost:3000/
典型结果对比( Bun 官方数据):
| 运行时 | RPS(每秒请求数) | 延迟 P50 | 延迟 P99 | 内存占用 |
|---|---|---|---|---|
| Bun Rust | ~95,000 | 1.2ms | 4.8ms | 28MB |
| Bun Zig | ~93,000 | 1.3ms | 5.1ms | 45MB(长期增长) |
| Node.js 22 | ~42,000 | 2.8ms | 12ms | 72MB |
八、这场大迁徙揭示的五个工程真相
经过对 Bun 从 Zig 到 Rust 重写的全面拆解,我们可以提炼出以下五个核心工程洞察:
真相一:语言选择是战术问题,架构稳定是战略问题
Bun 的 Zig 选择在初期是正确的——它提供了想要的性能和透明性。但当工程规模突破某个阈值时,语言的成熟度和生态支持开始超越语言的性能特性,成为主要矛盾。
这告诉我们:选语言要看项目所处阶段。初创期可以用激进的新语言快速迭代;成熟期需要切换到有更强保障的主流语言。
真相二:测试套件是新时代的"代码护城河"
Bun 能放心让 AI 批量翻译 1448 个文件,核心前提是有完整的测试套件作为安全网。测试覆盖率越高,AI 介入的空间越大——这个结论对所有想引入 AI 辅助编程的团队都有指导意义。
真相三:AI 编程的规模化临界点是百万行级
Bun 的案例证明:对于百万行级别的代码库,AI 机械翻译的可行性已经得到工程级验证。但这不意味着所有项目都应该这样做——关键是模块边界清晰、接口契约明确。
真相四:Anthropic 买 Bun 不是财务投资,是基础设施投资
AI 公司的核心竞争力是模型推理能力,但推理需要载体。当 Claude Code 依赖第三方 JavaScript 运行时并因此频繁崩溃时,控制关键依赖就成了自然选择。这对整个 AI 行业如何处理开源基础设施依赖有深远启示。
真相五:"人类审查代码"的前提正在被动摇
GitHub 能处理 10 万行的人类 PR,但无法优雅地渲染 100 万行的 AI PR。这不是 GitHub 的问题,而是整个工程基础设施都需要重新思考的问题:当代码来源从"人类编写"转向"AI 生成"时,CI/CD、代码审查、权限管理、合规审计的每个环节都需要重新设计。
结语:换心手术成功,但真正的考验才刚开始
Bun 从 Zig 到 Rust 的大迁徙,是 2026 年软件工程领域最具标志性的事件之一。它展示了 AI 辅助编程的最新能力边界,揭示了大型代码库维护的深层挑战,也让我们得以窥见 AI 公司如何将开源基础设施纳入自己的技术栈。
重写完成了,但真正的考验才刚开始:
- Rust 版本的长期稳定性如何?
- 社区能否接受 Anthropic 控制的核心基础设施?
- 0.2% 的未通过测试是否会演变成生产环境中的隐藏炸弹?
- 当更多项目开始用 AI 批量翻译代码时,"代码所有权"和"代码可维护性"如何重新定义?
这些问题没有现成答案。但有一点是确定的:2026 年的编程世界,已经和 2025 年大不相同了。
本文选题来源:GitHub Trending + OSCHINA 技术社区 + CSDN 开发者社区(2026年7月热点追踪)