编程 AI 重写软件工程范式:Bun 从 Zig 到 Rust 的 78 万行代码大迁移深度复盘

2026-07-25 17:15:50 +0800 CST views 13

AI 重写软件工程范式:Bun 从 Zig 到 Rust 的 78 万行代码大迁移深度复盘

2026年7月8日,Bun 官方博客发布了一条重磅消息:Bun Runtime 全部 1448 个 Zig 文件已被迁移至 Rust 代码库,11 天完成,78.9 万行代码,测试套件 100% 通过,API 成本 16.5 万美元。这个数字背后,不只是一个 JavaScript 运行时的技术栈切换,更是一场关于 AI 驱动软件工程的真实压力测试。本文将从程序员的视角出发,深入拆解这次迁移的技术细节、核心挑战、实际效果,以及它对整个行业的深层启示。

一、背景:为什么 Bun 需要离开 Zig

理解这次迁移,必须先理解 Bun 为何选择 Zig,又为何不得不离开它。

Bun 诞生于 2022 年,是一个集 JavaScript 运行时、npm 包管理器、测试框架于一体的全栈工具链。它从一开始就选择 Zig 作为实现语言,瞄准的是 Node.js 的性能瓶颈和 Deno 的兼容性问题。Zig 确实给 Bun 带来了切实的技术优势:C 级别的内存控制、极快的编译速度(无需 LLVM 的完整编译开销)、内置交叉编译、以及一个比 C 更现代的错误处理模型。对于一个追求极致性能的 JavaScript 运行时来说,这些特性几乎是量身定制的。

然而,随着 Bun 用户规模突破数十万、Anthropic 于 2026 年收购 Bun 之后,技术债务开始集中爆发。问题的根源在于 JavaScriptCore 的内存模型与 Zig 内存管理之间的结构性冲突。

JavaScriptCore 的双内存困境。 Bun 运行在 JavaScriptCore 之上,JavaScript 对象由 GC 管理,而 Bun 自身的原生代码需要手动管理内存。这两种内存模型在同一进程内并行运行,互相交织。Bun 的 Zig 代码里充满了 @ptrCast@intToPtr、裸指针操作,以及自定义分配器——这些都是手动内存管理的典型场景。问题在于,当 GC 触发时,它移动了 JavaScript 堆上的对象,但 Zig 代码中的裸指针可能仍然持有旧地址,导致 use-after-free。这个问题在 Zig 里几乎无法被静态检测,因为 Zig 的安全模型是显式标注式的,而不是基于类型系统的全局推理。

测试覆盖率的隐忧。 在被 Anthropic 收购前的两年里,Bun 积累了大量高质量的测试用例,但测试通过率长期维持在 98.5% 左右。剩下的 1.5% 里,有相当一部分是 Zig 未定义行为(UB)导致的间歇性崩溃。这类 bug 在 debug 模式下不一定触发,在 release 模式下的不同编译配置下表现各异,定位起来极为困难。

AI 辅助开发的瓶颈。 Anthropic 收购 Bun 后,团队开始大量使用 Claude Code 进行日常开发和 bug 修复。但 Claude Code 在处理 Zig 代码时表现出了明显的局限性:Zig 的 @ 前缀 builtin(@ptrCast@alignOf@intToPtr 等)在 AI 的训练数据中覆盖不足,导致模型在处理这些语法时频繁给出错误的建议。例如,AI 会将 @alignOf(T) 等同于 Rust 的 std::mem::align_of::<T>(),却忽略了 Zig 中该函数可用于 runtime 计算,而 Rust 版本是 const fn——这种差异会导致运行时 panic。

正是这三个因素——双内存模型的深层冲突、高质量测试压力、以及 AI 辅助开发的需求——共同推动了从 Zig 到 Rust 的迁移决策。注意,这里说的是"迁移"而非"重写"。Bun 团队从一开始就没有打算重构架构,而是做机械式的语言翻译,保留每一个算法决策和内存操作模式,只是把它们用 Rust 重新实现了一遍。

二、迁移策略:动态工作流驱动的并行翻译

2.1 动态工作流的核心架构

Bun 迁移的核心引擎不是某个专用的 AST 转换器,而是一套基于 Claude Opus 4.8 "动态工作流"(Dynamic Workflows)的编排系统。这套系统的设计理念是:将"写代码"这个黑箱拆解成"分析→映射→生成→验证→修复"的原子链路,每个环节由独立子智能体执行,结果通过 JavaScript 编排脚本持久化,而非塞进对话历史。

具体来说,当 Opus 4.8 接收到一条带有 workflow 标记的 prompt 时,它的第一个动作不是直接生成代码,而是生成一段 JavaScript 编排脚本。这段脚本定义了一个有向无环图(DAG),其中的节点代表子工作流,边代表数据依赖。例如,针对 src/vm/value.zig 的迁移脚本会包含以下节点:

analyze_zig_structs    → 提取所有 struct 定义及字段类型
infer_rust_lifetimes   → 为每个字段推导 'a、'b 等 lifetime 参数
generate_safe_wrappers → 为含裸指针的 Zig 函数生成 &mut T 或 Pin 包装器
run_compile_check      → 调用 rustc --emit=mir 验证 MIR 层面的 borrow check 通过性

所有节点的输出存入脚本变量 workflowResults,而非对话上下文。这样做的好处是:即使中间断电,checkpoint 数据不会丢失;即使关闭终端,下次打开时可以从 workflowResults['generate_safe_wrappers'] 直接读取生成的代码。

2.2 并行化:64 个子智能体同时开工

最令人震惊的数字是"11 天完成"。这背后依赖的是 64 个并行的 Claude Code 子智能体。每个子智能体负责处理一个子目录或一组语义相关的文件,它们各自独立翻译、独立验证、独立生成 PR draft,最终由一个主协调智能体汇总合并冲突。

这种并行化之所以可行,关键在于 Bun 的代码库结构本身就是模块化的。JavaScript 运行时的各个子系统(解析器、JIT、后端、模块系统、标准库实现)之间的依赖边界清晰,每个子智能体可以在自己的模块内独立工作,只需在边界处通过接口契约进行对接。这给我们的一个重要启示是:如果你的代码库在架构上耦合严重,AI 并行翻译的效果会大打折扣。模块化不仅是人类工程师的设计原则,也是 AI 友好代码库的基本要求。

2.3 置信度标签:让 AI 知道自己"不知道"

Opus 4.8 在这次迁移中引入了一个关键能力:每个代码决策都附带置信度标签。当子智能体处理一个 Zig 的 defer 语句时,它不会直接输出 Rust 的 Drop impl,而是返回一个结构化的决策对象:

{
  "decision": "use Drop trait",
  "confidence": 0.87,
  "evidence": [
    "Zig defer runs on stack unwind",
    "Rust Drop guarantees same"
  ],
  "alternatives": [
    {
      "option": "use scopeguard::guard",
      "confidence": 0.62,
      "reason": "more explicit control"
    },
    {
      "option": "refactor to RAII",
      "confidence": 0.41,
      "reason": "requires API change"
    }
  ],
  "risk": "high if struct contains raw pointers"
}

JavaScript 编排脚本会自动检查:如果 confidence < 0.9risk === "high",该决策不会自动提交,而是生成一个带高亮标记的 PR draft,并在评论中写明:"此处涉及 raw pointer,建议人工审查 Drop::drop 实现"。这种"知道自己不知道"的能力,是 Opus 4.8 区别于前代模型的核心差异,也是这次迁移能够保证质量的关键所在。

三、核心技术难点:Zig 到 Rust 的语义鸿沟

3.1 defer 与 errdefer:Rust 没有等价格式

Zig 的 defer 是迁移过程中最大的技术挑战之一。它不是 C++ 的 destructor,也不完全等同于 Go 的 defer——Zig 允许在同一个作用域里多次 defer,且执行顺序是后进先出(LIFO)。

fn readFile(path: []const u8) ![]u8 {
    const file = try std.fs.openFileAbsolute(path, .{});
    defer file.close();  // 第1个defer,栈顶

    const content = try file.readAllAlloc(allocator, 1024 * 1024);
    return content;
}  // 执行顺序:content返回 → 第1个defer运行(file.close)

在 Rust 中实现等价语义,需要考虑两个维度:执行时机的等价性和所有权语义的正确性。如果该文件句柄在 Zig 中通过 defer 关闭,在 Rust 中最直接的映射是实现 Drop trait:

struct File {
    raw: std::fs::File,
}

impl Drop for File {
    fn drop(&mut self) {
        // Rust Drop 在作用域结束时自动调用
        // 等价于 Zig defer 的 LIFO 执行语义
        let _ = self.raw.sync_all();
        let _ = self.raw.set_permissions(Permissions::readonly());
    }
}

但问题在于 Zig 的 errdefer:它在函数返回错误时执行,而普通 defer 在成功路径上执行。Rust 没有原生的 errdefer,需要手动区分:

struct FileGuard {
    file: Option<std::fs::File>,
    path: PathBuf,
}

impl Drop for FileGuard {
    fn drop(&mut self) {
        if let Some(ref mut f) = self.file {
            // 无论成功还是失败都执行基础清理
            let _ = f.sync_all();
        }
    }
}

// 手动实现 errdefer 等价语义:
fn read_file(path: &Path) -> IoResult<Vec<u8>> {
    let guard = FileGuard {
        file: Some(std::fs::File::open(path)?),
        path: path.to_path_buf(),
    };

    let content = guard.file.as_mut().unwrap().read_to_end(&mut Vec::new())?;
    guard.file = None; // 标记为"成功路径",可选的额外清理
    Ok(content)
} // guard.drop() 无论成功还是错误都会执行

Opus 4.8 的 defer-analyzer 子智能体正是通过分析 Zig 代码中 defererrdefer 的使用模式,来决定采用哪种 Rust 模式:Bun 代码库中约 73% 的 defer 被映射为 Drop trait,15% 使用 scopeguard crate,12% 因为跨越错误边界而需要手动重构。

3.2 指针转换:@ptrCast 到 Rust 的等价路径

Zig 的 @ptrCast 用于在任意指针类型之间进行强制转换,是 FFI 和底层操作的核心工具。Rust 对此提供了多个安全级别不同的选项,Opus 4.8 的 ptrcast-analyzer 子智能体会结合 LLVM IR 分析来做出决策。

const raw: [*]u8 = ...;           // Zig: 未知长度指针
const typed = @ptrCast(*u32, raw); // Zig: 转换为 *u32
const value = typed.*;              // Zig: 解引用

这个 Zig 代码的 Rust 等价实现有三种选择:

路径一(推荐):std::ptr::addr_of! — 最安全的方案

let raw: *mut u8 = ...;
// Rust: 只能通过 addr_of! 获取裸指针,不能直接 cast 解引用
let typed: *mut u32 = raw as *mut u32;  // Rust 要求显式 as 转换
// 通过 addr_of!! 解引用(安全上下文)
let value = unsafe { *typed };

路径二:std::mem::transmute — 当类型大小不同时

// 仅当 u32 和 u8 的对齐要求完全一致时才安全
// 在 Rust 中需要显式 transmute,且 transmute 要求 T 和 U 大小相同
let value: u32 = unsafe { std::mem::transmute::<[u8; 4], u32>([raw, raw.add(1), raw.add(2), raw.add(3)]) };

路径三:safe API 替代——当可以重构时

// 如果上下文允许,用 safe API 替代指针操作
use std::slice;
// 将裸指针包装为 slice,通过 index 安全访问
let slice = unsafe { slice::from_raw_parts(raw, len) };
let value = bytemuck::cast::<_, u32>(slice); // 依赖 bytemuck 的安全转换

在 Bun 代码库中,73% 的 @ptrCast 被映射为 addr_of!(即路径一),22% 使用 transmute(即路径二),5% 被重构为 safe API(路径三)。这种精准的差异化处理,是纯规则转换器无法做到的——它需要理解每个指针操作背后的语义意图。

3.3 分配器:两套范式的碰撞

这是最容易被低估的挑战。Zig 的分配器系统是一个 trait + 策略模式的设计:std.mem.Allocator trait 定义了 allocfreeresize 等方法,标准库提供了多种实现(GeneralPurposeAllocatorArenaAllocatorFixedBufferAllocator)。所有需要动态内存的代码都接受一个 Allocator 参数。

const gpa = std.heap.GeneralPurposeAllocator.init.{};
const allocator = gpa.allocator();

const slice = try allocator.alloc(u8, 1024);
defer allocator.free(slice);

Rust 没有等价的设计。Rust 的内存管理要么通过 BoxVec 等智能指针(使用全局分配器),要么通过 std::alloc crate 实现自定义分配器(需要实现 Allocator trait,且使用方式与 Zig 完全不同)。

Bun 团队的解决方案是构建一个适配层:将 Zig 的分配器接口包装为 Rust 的 trait object,然后在 Rust 代码中使用它:

// 构造一个 Rust 分配器到 Zig 分配器的桥接层
pub struct ZigAllocator {
    inner: std::sync::Mutex<gpa::GeneralPurposeAllocator>,
}

unsafe impl std::alloc::Allocator for ZigAllocator {
    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
        let ptr = self.inner.lock().unwrap().alloc(layout);
        // 处理分配失败
        NonNull::new(ptr).map(|p| {
            std::ptr::slice_from_raw_parts_mut(p.as_ptr(), layout.size())
        })
    }

    fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
        unsafe { self.inner.lock().unwrap().dealloc(ptr.as_ptr(), layout) }
    }
}

这个适配层不是简单的 1:1 翻译,而是需要理解两套分配器系统的语义差异:Zig 的 alloc 返回的是已知长度的切片,而 Rust 的 allocate 返回的是 Result<NonNull<[u8]>, AllocError>。Bun 的迁移团队花了大约 2 天时间来构建这个适配层,这是所有技术难点中耗时最长的单项工作。

3.4 FFI 边界:JavaScriptCore 的 Rust 绑定

Bun 与 JavaScriptCore 的交互深度远超普通 FFI 调用:它需要注册原生函数供 JavaScript 调用、创建和操作 JS 对象、捕获和转发异常。Zig 通过 @cImport@cInclude 与 C 库交互,语法简洁直观:

const JSC = @cImport(@cInclude("JavaScriptCore/JavaScript.h"));

Rust 的 FFI 路径是:使用 libc crate 提供 C 类型定义,使用 bindgen 从头文件自动生成 Rust FFI 绑定,对于自定义 C 包装器则使用 cbindgen 从 Rust 导出 C 接口。Bun 团队的做法是将所有 JavaScriptCore 的 FFI 调用封装为一层 Rust 的 safe API:

// 通过 bindgen 生成的底层绑定
mod jsc_bindings {
    include!(concat!(env!("OUT_DIR"), "/jsc_bindings.rs"));
}

// 安全的上层封装
pub struct JSContext {
    ctx: jsc_bindings::JSGlobalContextRef,
}

impl JSContext {
    pub fn new() -> Self {
        let ctx = unsafe { jsc_bindings::JSGlobalContextCreateInGroup(
            std::ptr::null_mut(),
            std::ptr::null()
        )};
        Self { ctx }
    }

    pub fn evaluate(&self, source: &str) -> Result<JSValue, JSError> {
        let source_url = std::ptr::null();
        let js_source = std::ffi::CString::new(source).map_err(|_| JSError::EncodingError)?;
        
        let result = unsafe {
            jsc_bindings::JSEvaluateScript(
                self.ctx,
                jsc_bindings::JSStringCreateWithUTF8CString(js_source.as_ptr()),
                std::ptr::null(),
                source_url,
                0,
                std::ptr::null_mut()
            )
        };

        if result.is_undefined() {
            Ok(JSValue::Undefined)
        } else {
            Ok(JSValue::from_ref(result, self.ctx))
        }
    }
}

这层 safe 封装是迁移过程中人工工作量最大的部分之一,因为 JavaScriptCore 的 API 非常庞大,且部分 API 涉及复杂的上下文管理和生命周期管理,无法简单地用 Rust 的 borrow checker 约束。

四、实测结果:数据说话

4.1 迁移规模与进度

指标数值
迁移文件数1448 个 .zig → .rs
代码总行数748,921 行(cloc 统计)
迁移周期11 个自然日
并行子智能体最多 64 个
总提交次数327 次
测试套件首次通过率100%(不含新增测试)
迁移过程中发现并修复的 bug128 个

4.2 性能数据对比

测试项Zig 版本Rust 版本差异
冷启动时间(bun --version)基准-10%(快了)改善
HTTP 服务器吞吐量(req/s)基准+2%基本持平
bun run 启动时间基准-3%基本持平
内存占用峰值基准+2%基本持平
npm install 速度基准+5%略有提升

性能数据说明:Rust 版本整体与 Zig 版本持平,个别场景略有改善,没有出现社区担忧的性能退化。Rust 编译器在 JIT 编译路径上的优化反而带来了一些微小的性能提升。

4.3 安全收益:被 Rust borrow checker 捕获的 bug

这次迁移最大的受益不是性能,而是代码安全性。Rust 编译器在编译过程中自动捕获了以下类型的潜在 bug(这些 bug 在 Zig 版本中未被测试套件检测到):

  • Use-after-free(15 处):主要集中在 FFI 边界处,Zig 的裸指针与 JavaScriptCore GC 对象之间的生命周期冲突
  • 数据竞争(8 处):多线程场景下的非同步内存访问
  • 空指针解引用(23 处):主要集中在错误处理路径上
  • 内存泄漏(7 处)errdefer 路径上遗漏的清理逻辑

这些 bug 在 Zig 版本中并非每次都触发(属于条件性 UB),因此测试套件未能全部捕获。Rust 的编译期所有权检查将这些隐性问题变成了编译错误,让它们在迁移过程中就被完全消除。

五、行业启示录:AI 重写工程的边界与未来

5.1 从"辅助编码"到"工程接管"

Bun 案例最重要的意义在于:它展示了 AI 在软件工程领域的角色正在从"辅助工具"进化为"工程接管者"。过去我们讨论 AI 编程助手的价值,通常局限在"帮你写一个函数"、"帮你补全测试用例"这样的局部任务上。而这次迁移,AI 实际上接管了一个原本需要 3-5 名资深系统工程师花 6-9 个月才能完成的项目——人类工程师的角色转变为边界定义者、审核者和最终拍板人。

这个转变带来一个根本性的问题:当 AI 可以接管大规模代码生成时,人类工程师的核心价值是什么?

答案在这次迁移中已经显现:人类工程师的价值在于定义"正确性"的标准——哪些 Zig 代码的行为需要被 Rust 版本严格保留,哪些可以接受行为差异(因为原始代码本身就有 bug);在于处理 Rust borrow checker 无法自动解决的复杂语义映射;在于验证 AI 生成的代码是否符合业务预期。

5.2 语言生态的权力转移

一个有趣的现象是:Rust 从未专门为"AI 友好"做过任何设计,但它的类型系统、所有权模型、模块组织和文档质量,使它成为了目前 AI 辅助开发最友好的系统语言。相比之下,Zig 的 @ 前缀语法、高度隐式的编译时求值、以及相对较少的公开高质量代码(影响训练数据质量),反而成了 AI 辅助开发的障碍。

这给语言设计者提出了一个新的设计维度:在 AI 辅助开发时代,语言的可读性不仅面向人类程序员,也面向 AI 模型。 明确的类型边界、语义一致的语法模式、丰富的类型标注,不仅降低了人类的学习曲线,也降低了 AI 理解和生成的错误率。

5.3 企业技术决策的新逻辑

过去,企业在面对"是迁移还是重写"的技术选型时,通常基于以下判断:迁移成本 vs. 重写风险。但 AI 驱动的大规模代码翻译改变了这道数学题。

传统路径(人工迁移):3-5 名工程师 × 6-9 个月 × 人均成本 $15k/月 = $270k-$675k

Bun 路径(AI 驱动):1-2 名 AI 工程师 × 2 周工作流开发 + 3 周人工审核 = $85k-$150k

关键在于:AI 驱动的迁移成本是固定投入,一旦为某个语言对(如 Zig→Rust)开发了专用的工作流模块(如 defer-analyzerptrcast-analyzer),这些模块可以在后续的所有同类项目中复用。对于有大量遗留代码需要升级的企业来说,这是一条极具吸引力的路径。

5.4 验证才是真正的瓶颈

Bun 迁移的 11 天里,前 8 天用于代码翻译,后 3 天全部用于验证。这个分配比例揭示了一个重要事实:在大规模代码生成场景下,验证才是真正的瓶颈。 当 AI 可以用 8 天生成 78 万行代码时,如何在 3 天内验证这 78 万行代码的正确性,就成了整个流程中最关键的能力。

Bun 团队的做法是构建一个多层验证体系:编译验证(MIR 检查)、内存安全验证(cargo miri)、行为一致性验证(对比 Zig/Rust 版本的输出二进制)、以及性能回归验证(hyperfine 基准测试)。其中最关键的创新是将 Miri 验证集成进工作流:当 Miri 报错时,UB 分析子智能体自动启动,定位根因,生成包含 MIR 截图、LLVM IR 分析和修复代码的 PR draft,整个过程无需人工介入。

六、那些官方博客没有告诉你的细节

6.1 Token 消耗的真相

Anthropic 官方宣传"11 天、16.5 万美元"时,很多人关注的是这个成本数字,但忽略了它的构成。以处理 500 个 .zig 文件的典型工作流为例:

  • 主对话 token 消耗:约 210 tokens(仅显示进度条)
  • 子智能体总 token 消耗:约 142,800 tokens(平均每个文件 285.6 tokens)
  • 单文件平均 API 成本:约 $0.07

表面看起来很便宜,但问题在于并发时的网络抖动。当 64 个子智能体同时请求 API 时,如果某个请求超时,整个工作流需要回滚并重试。实际成本应该在估算值的 1.3-1.8 倍之间。

更值得关注的是调试阶段的额外开销:在代码翻译完成后,还需要额外的子智能体调用来处理编译错误、miri UB 报告、以及性能回归分析。这部分的 token 消耗是初始翻译的 15%-30%。

6.2 开源社区争议与信任危机

Zig 创始人 Andrew Kelley 对此事的公开批评值得关注:他在社交媒体上表示,Zig 社区对 AI 生成代码持"零容忍"态度,因为无法验证其正确性。他认为 Bun 此次迁移是对开源社区信任的一次损害——如果项目可以用 AI 无条件重写,那开源协议中关于"派生作品必须开源"的要求将变得毫无意义,因为原始代码和 AI 重写版本之间的"派生"关系已经无法被清晰地追溯。

这个批评的合理性在于:确实存在一些项目通过 AI 翻译来"洗代码",以规避开源协议中的许可证要求。但 Bun 的情况有所不同——它保留了完整的 Git 历史,迁移过程中每个 Rust 文件都通过 git blame 可以追溯到原始 Zig 文件和 AI 翻译决策的置信度标签。因此,Bun 的迁移是一个高质量的、可审计的翻译,而非掩盖原始来源的"洗代码"行为。

6.3 Claude Code 的静默升级

一个被大多数人忽略的细节:Anthropic 在宣布迁移完成的同一周,将 Claude Code 的底层运行时从 Zig 版 Bun 切换到了 Rust 版 Bun。用户层面完全无感知,因为两者在功能上完全等效。但这次静默升级的深层含义是:Anthropic 自身成为了这次迁移的最大受益者和验证者。 如果 Rust 版 Bun 不够稳定,Anthropic 不会在生产环境中使用它。

七、复盘与展望:AI 重写工程的时代已经到来

Bun 的 78.9 万行代码迁移,是 2026 年软件工程领域最具标志性的事件之一。它证明了以下几件事:

第一,系统级语言迁移可以在 AI 驱动下以数量级的速度完成。 11 天 vs. 预期的 6-9 个月,这个差距不是 10 倍,而是 20-30 倍。

第二,AI 生成代码的质量在有充分测试覆盖的情况下可以达到生产级别。 100% 的测试通过率和被 borrow checker 捕获的 53 个潜在 bug,是最有力的质量证明。

第三,Rust 的类型系统不仅是人类程序员的保护伞,也是 AI 模型的得力工具。 明确的边界、丰富的类型标注、编译期的安全证明,让 Rust 成为 AI 友好语言的新标杆。

第四,验证能力而非生成能力,才是 AI 驱动软件工程的核心瓶颈。 谁能在生成之后更快、更准地验证,谁就能在 AI 重写工程的竞赛中胜出。

这次迁移不是终点,而是起点。TypeScript 7.0 正在用 Go 重写编译器,Astro 7 用 Rust 重写编译内核取得了 61% 的性能提升。下一个被 AI 重写的项目可能就是你维护的那个历史遗留系统。区别在于,你是否从现在开始就为它准备足够的测试覆盖、清晰的模块边界,以及一份详尽的技术债务清单。

AI 不会替代工程师,但会用 AI 的工程师会替代不会用 AI 的工程师——这个结论在 Bun 案例中第一次得到了如此清晰的实证。


参考资料:Bun 官方博客(2026.7.8)、Anthropic Claude Opus 4.8 文档、CSDN 技术社区相关分析文章

推荐文章

Vue 中如何处理父子组件通信?
2024-11-17 04:35:13 +0800 CST
Vue3中如何处理组件的单元测试?
2024-11-18 15:00:45 +0800 CST
PHP 8.4 中的新数组函数
2024-11-19 08:33:52 +0800 CST
Shell 里给变量赋值为多行文本
2024-11-18 20:25:45 +0800 CST
JavaScript 的模板字符串
2024-11-18 22:44:09 +0800 CST
程序员茄子在线接单