编程 Bun 从 Zig 到 Rust:AI 用 11 天重写百万行运行时,性能、供应链与开源信任的三重实验

2026-07-26 02:14:31 +0800 CST views 10

Bun 从 Zig 到 Rust:AI 用 11 天重写百万行运行时,一场性能、供应链与开源信任的三重实验

一句话概括:2026 年,Bun 悄悄把底层从 Zig 换成了 Rust,Claude Code 也跟着换了运行时,Linux 下启动快了 10%,但几乎没人察觉。这背后不是一次普通的技术升级,而是 AI 全自动重写代码库、资本收购开源项目、以及"开源"退化成"源码可见"的三重信号弹。本文从一个后端工程师的视角,把这件事从架构、代码、性能到治理彻底拆开讲一遍。

一、背景:一个"四年前赌 Zig,四年后一夜换 Rust"的故事

如果你写过前端或 Node.js 后端,大概率听过 Bun 这个名字。它 2022 年横空出世,一个月内在 GitHub 拿到 2 万 star,2022 年直接成了当年最受欢迎的 JavaScript 项目。

Bun 的定位很"反 Unix 哲学"——别人是"一个工具做好一件事",它偏要做全家桶:

  • 运行时(Runtime):直接跑 JavaScript/TypeScript,不用 tsc 预编译
  • 包管理器(Package Manager):替代 npm/yarn/pnpm,bun install 快到离谱
  • 打包器(Bundler):替代 Webpack/esbuild/Parcel,官方宣称比 Webpack 快 220 倍
  • 测试运行器(Test Runner):内置 bun test
  • 任务运行器bun run

它敢这么做的底气,一半来自 JavaScriptCore(苹果 Safari 的 JS 引擎,比 Node.js 用的 V8 启动更快),另一半来自它当年一个非常"特立独行"的选择——用 Zig 写底层

Zig 是一门年轻的系统级语言,主打"比 C 更安全、比 C++ 更简单、无隐藏控制流"。四年前 Bun 押注 Zig,成了整个 Zig 生态里最重要、最能打的生产级项目——某种程度上,Bun 就是 Zig 最亮的一张名片。

然后,2026 年 5 月 11 日,创始人 Jarred Sumner 在 X 上发了一条推文:

"Bun v1.3.14 将于明日发布。如果我们合并 Rust 重写版本,这将是 Zig 的最后一个版本。"

就这一句话,Zig 版 Bun 被判了死刑。四年的技术积累,一条推文了结。而更炸裂的是重写的方式:用 AI,六到十一天,重写了将近一百万行代码。

这篇文章我们不站队,只讲清楚三件事:为什么要换、AI 是怎么换的、换完之后你作为开发者该怎么办。

二、先补底层课:一个 JS 运行时的"引擎盖下面"到底有什么

要理解"从 Zig 换到 Rust"意味着什么,得先知道运行时的底层到底在忙什么。很多人以为"运行时 = 一个跑 JS 的解释器",其实远不止。

一个现代 JS 运行时(无论 Node、Deno 还是 Bun)大致由这几层组成:

┌─────────────────────────────────────────────┐
│  你的 JS/TS 代码                                │
├─────────────────────────────────────────────┤
│  标准库 / 内置 API(fs、http、crypto、sqlite…) │  ← 这层是"胶水",用系统语言写
├─────────────────────────────────────────────┤
│  JS 引擎(Bun=JavaScriptCore / Node=V8)        │  ← 解析、JIT、GC
├─────────────────────────────────────────────┤
│  事件循环 + I/O 多路复用(epoll/kqueue/io_uring)│  ← 异步的心脏
├─────────────────────────────────────────────┤
│  内存分配器(mimalloc 等)+ 系统调用             │
└─────────────────────────────────────────────┘

Bun 用 Zig 写的,主要是中间那几层"胶水":内置 API 的实现、事件循环调度、bundler、包管理器的解析逻辑、以及大量和 JavaScriptCore 交互的 FFI 绑定。JS 引擎本身(JavaScriptCore)是 C++ 写的,那部分没动。

这里有个关键点很多人忽略:运行时的性能瓶颈,往往不在 JS 引擎,而在这层"胶水"。 比如 bun install 快,不是因为 JS 跑得快,而是因为它的依赖解析、tar 解压、文件写入全用系统级语言并发实现,绕开了 npm 那套用 JS 写的慢吞吞逻辑。

所以,"换语言"换的就是这层胶水。这层胶水有多重?将近一百万行。它要处理:

  1. 手动内存管理:Zig 没有 GC,每一块 buffer 都要自己 alloc/free
  2. 和 C++ 引擎的边界交互:大量原始指针(raw pointer)传来传去
  3. 高并发 I/O:一个进程要扛住成千上万的并发连接
  4. 跨平台系统调用:Linux 的 epoll/io_uring、macOS 的 kqueue、Windows 的 IOCP

这层胶水的每一个 bug,都可能是段错误(Segmentation Fault)、内存泄漏,或者更隐蔽的数据竞争。这也是后面故事的核心矛盾点。

三、为什么非换不可:内存安全、AI 亲和性、治理权,三个理由缺一不可

Bun 从 Zig 换 Rust,表面看是技术选型,实际上是三股力量合流的结果。

3.1 内存安全:Zig 的"半吊子安全"扛不住海量并发

Zig 号称比 C 安全,但本质上仍然要手动管理内存。它给了你一些工具(比如 debug 模式下的边界检查、defer 释放),但编译器不会在编译期拦住你写出 use-after-free 或数据竞争。

Rust 不一样。Rust 的**所有权(ownership)+ 借用检查(borrow checker)**在编译期就能拦掉一大类内存错误:悬垂指针、双重释放、数据竞争。对一个要处理海量并发请求的 JS 运行时来说,这个保证的价值极高——你不希望某个用户的一个畸形请求,触发底层一块 buffer 的 use-after-free,直接把整个进程干崩。

举个最典型的对比。Zig 里手动管理一块 buffer:

// Zig:编译器不拦你,忘了 free 就泄漏,free 早了就 UAF
const buf = try allocator.alloc(u8, len);
defer allocator.free(buf);  // 靠人记得写 defer
processData(buf);
// 如果这里 processData 内部又存了 buf 的指针,defer 之后就是悬垂指针,编译器沉默

同样的逻辑在 Rust 里:

// Rust:所有权转移 + 生命周期,编译器全程盯着
fn process(data: Vec<u8>) {
    // data 在这个函数结束时自动 drop,没有手动 free
    // 如果你想在别处保存 &data,借用检查器会强制你标注生命周期
    // 写不出悬垂指针 —— 除非你主动写 unsafe
}
let buf = vec![0u8; len];
process(buf); // 所有权移交,buf 之后不能再用,编译器保证

理论上,Rust 版本应该更稳。这是官方叙事的核心卖点。

3.2 AI 亲和性:Zig 明确禁止 AI 辅助贡献,这对一家 AI 公司是"釜底抽薪"

这是很多技术文章会漏掉、但其实是决定性的一条。

Zig 社区明确禁止 AI 辅助的代码贡献。 而 Bun 的母公司 Oven 在 2026 年初被 Anthropic(Claude 的东家)收购了。

你品一下这个矛盾:一家把"用 AI 写代码"当核心业务的公司,它的拳头产品 Claude Code 每月创造数十亿美元营收,而这个产品的底层运行时,却依赖一门禁止用它自家最擅长的工具去改进的语言。

这等于砍掉了 Anthropic 的核心杠杆。如果继续用 Zig,Anthropic 就无法用 AI 大规模地维护、优化、修 bug。换成 Rust——一门 AI 训练数据极其丰富、生态成熟的语言——AI 就能全程接管。

后面的事实印证了这一点:Bun 的 Rust 重写,正是用 Claude Code 调动几十个 AI Agent 完成的。这本身就是一次"AI 能不能重写整个运行时"的商业验证。

3.3 治理权:收购之后,社区不再有发言权

Anthropic 收购 Oven 之后,Bun 的决策权就完全归内部了。重写决定几乎没有社区讨论,PR 合并到主分支的速度快得离谱,5000 多个 Zig 时代积累的 issue 被批量关闭,理由是"Zig 版本已废弃"。

对 Zig 社区来说,这是双重打击:技术上失去了最重要的生产级项目,情感上像被"背刺"。Zig 创始人 Andrew Kelley 公开评论说 Bun 的 Zig 代码质量堪忧,是"如何不写 Zig 代码的典型案例"——这话与其说是技术批评,不如说是情绪发泄。

三个理由叠加,换 Rust 从商业角度看几乎是必然。

四、AI 重写的工程真相:这不是"重构",是"直译"

这是整件事最值得程序员深挖的部分。11 天、近百万行、约 16.8 万美元 token 成本(因为用自家模型,市价可能要数百万),在 Linux x64 glibc 上通过了现有测试套件的 99.8%。

听起来像魔法。但拆开看,你会发现它有明确的能力边界。

4.1 它做的是 transpilation(直译),不是 redesign(重设计)

关键区别:AI 做的是逐行、保语义的语言翻译,代码结构和架构几乎原封不动,只是把 Zig 语法换成 Rust 语法。

这就像把一本中文小说翻译成英文——句子结构可能微调,但情节、章节、人物一个不变。如果原著逻辑有硬伤,翻译版照样有。

事实上,Bun 的 Zig 版本本身就被批评是"把 esbuild 从 Go 逐行移植到 Zig"。所以现在这个 Rust 版本,是**经过两次直译(Go → Zig → Rust)**的产物。代码质量很难说有质的飞跃。

这解释了一个反直觉的现象:Rust 版本里塞满了 unsafe 代码块。

4.2 unsafe 密度:把 Zig 的裸指针原样搬进 Rust,加个标签就算"安全"了?

Rust 的内存安全保证,只在"安全 Rust"里成立。一旦你写 unsafe {},就等于告诉编译器"这块我自己负责,别管我"——所有权和借用检查在 unsafe 块里被绕过。

社区追踪数据显示,Bun 的 Rust 重构版合并后两个月,unsafe 代码数量维持在约 13,900 处,几乎没下降。为什么这么多?因为 AI 在直译时,遇到 Zig 里的裸指针操作,最省事的做法就是包一层 unsafe 原样搬过来。

我用一段示意代码说明这个"假安全"陷阱。Zig 里常见的裸指针别名操作:

// Zig:两个指针指向同一块内存,直接改
var data: [1024]u8 = undefined;
const p1: [*]u8 = &data;
const p2: [*]u8 = &data;
p1[0] = 1;
p2[0] = 2; // 别名,Zig 不管

直译到 Rust 后,往往变成这样:

// Rust:为了"翻译"上面的逻辑,塞进 unsafe
let mut data = [0u8; 1024];
let p1 = data.as_mut_ptr();
let p2 = data.as_mut_ptr();
unsafe {
    *p1 = 1;
    *p2 = 2; // 两个 &mut 别名 —— 违反 Rust 的 aliasing 规则!
    // 编译器不报错(因为在 unsafe 里),但这是 UB(未定义行为)
    // 会导致优化器做出错误假设,埋下诡异 bug
}

这里的致命点:Rust 编译器(LLVM 后端)会假设 &mut 引用是独占的,据此做激进优化。如果你在 unsafe 里制造了别名,优化器的假设就破产了,可能产生看似随机、极难复现的 bug。

一位 Rust 资深开发者评论说,Bun 的 unsafe 密度比 Deno 高出几倍,很多 unsafe 块根本不满足 Rust 的别名安全要求。换句话说:安全只是表面文章。你从 Zig 搬来的内存问题,加个 unsafe 标签,并没有消失,只是被藏起来了。

这就引出一个尖锐的问题——unsafe 到底是"安全边界"还是"甩锅标记"? 理想情况下,unsafe 应该是"我在这里做了编译器验证不了但我用别的方式证明过安全的操作";但直译式的 unsafe,更像是"我懒得想清楚,先跑通再说"。

4.3 测试驱动验证的黑箱边界

AI 重写靠什么保证正确?靠现有测试套件——通过率 99.8%。这很高,但反过来说:

  • 那 0.2% 是什么?没人系统性回答过。
  • 测试覆盖不到的地方,就是纯黑箱。 尤其是那些 Zig 版本本身行为就模棱两可的边缘情况。
  • AI 在机械翻译时,不会主动发现并修复原有 bug,只会原样复制。它不是重构工程师,是翻译器。

有用户已经报告,Rust 版本在处理某些边缘情况时行为和 Zig 版本不同——不能说一定是 bug,但足以让谨慎的人却步。也有人报告 Claude Code 出现段错误(Segfault)、标签页卡死,以及多会话时内存占用超过 3GB。段错误在一个"内存安全语言"重写的产品里出现,本身就很讽刺——如果代码真的被"正确"重写了的话。

(补充一句公道话:3GB 内存和部分卡死,很大程度是 JavaScript 单线程架构本身的锅,跟底层用 Zig 还是 Rust 没直接关系。但 Rust 版本显然也没顺手解决这些根本问题——因为它只是直译。)

五、代码实战:从性能优化 PR 看真正的工程细节

抛开争议,这次重写的 PR(oven-sh/bun #30412)里有很多值得学习的底层性能优化技巧。这些是真功夫,无论用哪门语言都通用。我挑几个讲。

5.1 用栈上小向量避免堆分配(SmallVec)

PR 里有一条:LineOffsetTable SmallVec<[i32;256]>。这是 bundler 里计算 source map 时用来存每行偏移量的表。

普通做法是用 Vec<i32>,但 Vec 一定在堆上分配。对于大多数文件,行数不会超过几百行。于是用 SmallVec<[i32; 256]>前 256 个元素放栈上,超了才 fallback 到堆

use smallvec::SmallVec;

// 大多数文件 < 256 行,全程零堆分配
let mut line_offsets: SmallVec<[i32; 256]> = SmallVec::new();
for (i, byte) in source.bytes().enumerate() {
    if byte == b'\n' {
        line_offsets.push(i as i32);
    }
}
// 只有超大文件才真正 malloc,命中率极低

在 bundler 这种"对成千上万个文件循环处理"的热路径上,省掉每个文件一次堆分配,累积起来就是可观的性能收益。这对应 PR 里的 commit message:"match Zig s..."——即对齐 Zig 版本原本就有的栈上暂存策略。

5.2 跳过每次 mmap 的 prctl 系统调用

另一条:define MI_NO_SET_VMA_NAME — skip prctl(PR_SET_VMA) per mmap

mimalloc(Bun 用的内存分配器)在 Linux 上每次 mmap 一块内存,默认会调 prctl(PR_SET_VMA_ANON_NAME) 给这块内存区域命名(方便调试时在 /proc/pid/maps 里看名字)。但这个 syscall 在高频分配场景下是纯开销。

// mimalloc 默认行为(伪代码)
void* p = mmap(...);
prctl(PR_SET_VMA_ANON_NAME, p, size, "mimalloc"); // 每次都调,调试友好但慢

定义 MI_NO_SET_VMA_NAME 后直接跳过这个 syscall。用一点点调试便利,换高频分配路径上的性能。 这种"知道自己在生产环境不需要 VMA 名字"的取舍,是系统级优化的典型思路。

5.3 惰性初始化 arena,避免每个 worker 一次堆创建

lazy JsonCache arena — avoid mi_heap_new per bundler worker:bundler 用多个 worker 并行处理,每个 worker 原本都会 mi_heap_new() 创建一个独立堆。但不是每个 worker 都会用到 JSON 缓存。改成惰性创建——真正用到时才 new:

// 惰性初始化:用到才建 arena
struct BundlerWorker {
    json_cache: OnceCell<Arena>, // 延迟到首次访问
}

impl BundlerWorker {
    fn json_arena(&self) -> &Arena {
        self.json_cache.get_or_init(|| Arena::new())
        // 不碰 JSON 的 worker,永远不会付这笔创建成本
    }
}

这三个优化的共同哲学:在热路径上,把"以防万一"的成本砍到"用到才付"。 这才是运行时性能工程的日常——不是什么惊天动地的算法,而是无数个这种小取舍的累积。

5.4 实际体验:Bun 你现在能怎么用

如果你想现在体验 Rust 版本(canary 状态):

# 安装 Bun(稳定版仍是 Zig 主导,Rust 在 canary)
curl -fsSL https://bun.sh/install | bash

# 切换到包含 Rust 重写的 canary 版本
bun upgrade --canary

# 验证版本
bun --version

# 常见用法演示
bun init                    # 初始化项目
bun install                 # 装依赖,比 npm 快数倍
bun run index.ts            # 直接跑 TS,无需 tsc
bun test                    # 内置测试运行器
bun build ./index.ts --outdir ./dist --minify  # 打包

一个能体现 Bun "全家桶 + 原生性能"的小例子——内置 SQLite + HTTP 服务,零外部依赖:

// server.ts —— 用 Bun 内置能力起一个带 SQLite 的 HTTP 服务
import { Database } from "bun:sqlite";

const db = new Database(":memory:");
db.run(`CREATE TABLE visits (id INTEGER PRIMARY KEY, ts INTEGER)`);

const insert = db.prepare("INSERT INTO visits (ts) VALUES (?)");
const count = db.prepare("SELECT COUNT(*) AS c FROM visits");

Bun.serve({
  port: 3000,
  fetch(req) {
    insert.run(Date.now());
    const { c } = count.get() as { c: number };
    return new Response(`访问次数:${c}\n`);
  },
});

console.log("跑在 http://localhost:3000");
bun run server.ts
# 另开终端
curl http://localhost:3000   # 访问次数:1
curl http://localhost:3000   # 访问次数:2

注意 bun:sqlite 是内置的——不用 npm install better-sqlite3,不用编译原生模块。Bun.serve 也是原生实现,性能远超用 JS 手写的 http server。这些"内置能力"正是那层胶水的价值,也正是被从 Zig 直译到 Rust 的那部分代码。

5.5 用 Bun FFI 直接调 Rust 库(顺便理解运行时的 FFI 边界)

既然聊到运行时和系统语言的边界,演示一下 Bun 怎么直接调用一个 Rust 编译出的动态库——这也是理解"胶水层"如何跨越语言边界的最好方式:

// mylib.rs —— 编译成 cdylib
#[no_mangle]
pub extern "C" fn fib(n: u32) -> u64 {
    match n {
        0 => 0,
        1 => 1,
        _ => {
            let (mut a, mut b) = (0u64, 1u64);
            for _ in 2..=n { let t = a + b; a = b; b = t; }
            b
        }
    }
}
rustc --crate-type cdylib mylib.rs -o libmylib.dylib   # macOS
# Linux: rustc --crate-type cdylib mylib.rs -o libmylib.so
// call.ts —— Bun 的 FFI 直接加载
import { dlopen, FFIType, suffix } from "bun:ffi";

const { symbols } = dlopen(`libmylib.${suffix}`, {
  fib: { args: [FFIType.u32], returns: FFIType.u64 },
});

console.log(symbols.fib(50)); // 12586269025n

bun:ffi 让 JS 直接调 C ABI 函数,中间没有 Node.js N-API 那层开销。这条边界,恰恰就是内存安全最容易出事的地方——数据从受管的 JS 世界,跨进裸指针的系统世界。谁来保证这块内存的生命周期?在 Zig 里是人,在(安全)Rust 里是编译器,在 unsafe Rust 里……又回到了人。

六、供应链与开源信任:当一个开源项目被 AI 一夜重写

技术之外,这件事真正的重量在治理层面。

6.1 "开源"退化成"源码可见"

Bun 仍然是 MIT 许可证,代码仍然公开。但收购之后,社区既没被咨询,也没被提前通知。重构 PR 突然出现在主分支,社区成员只有两个选择:接受,或离开。

这背离了开源的核心——透明、协作、共识决策。当 Jarred 说"无聊即是好事"(意思是用户没感知到变化,说明迁移成功)时,他说的没错,但他没说的是:开源社区本身已经被排除在决策链之外。 "开源"在这里退化成了"你能看源码,但你影响不了它往哪走"。

6.2 一个被低估的法律灰区:AI 生成代码的版权

这是企业最该警惕的一点。根据美国版权局 2025 年的判例,完全由 AI 生成的内容不享有版权保护。

Bun 的 Rust 版本是 AI 基于人工写的 Zig 代码"翻译"来的。中间有多少"人类创造性投入"?这是个灰色地带。如果未来有人 fork 这个版本,声称"AI 翻译的代码不构成人类原创作品,因此不受原 MIT 许可证约束",法律上可能真站得住脚。

对所有依赖开源的企业,这敲响警钟:当一个依赖被 AI 大规模重写后,它的法律地位变得模糊。 许可证还管不管用?你还能不能放心引用?目前没人能给确定答案。

6.3 供应链集中度风险

Claude Code 每月数十亿美元营收,底层完全依赖一个被自家收购的运行时。从供应链安全看,这是把金库钥匙和保险柜放进了同一个房间——垂直整合带来效率,也带来单点风险。一旦 Bun 底层出严重问题,波及的是 Claude Code 的百万用户,连回滚到"别家运行时"的选项都没有。

七、给开发者的实操建议:升还是不升,这是个选择题

抛开宏大叙事,落到你我每天的工具链上,就三种角色:

如果你是 Bun 用户:

  • Rust 版本目前是 canary,功能基本可用,稳定性不保证。
  • 生产环境后端服务:暂时别动,继续用稳定版。
  • 开发工具链(构建脚本、测试、CI):升级风险相对可控,出问题回滚快,可以尝鲜。
  • 升级前先跑全量测试,特别注意边缘行为(编码、流、错误栈、FFI 边界)。

如果你是 Claude Code 用户:

  • 没有选择权——底层 Bun 版本跟着客户端走。
  • 遇到终端渲染异常或段错误,试试重启会话或 claude --resume
  • 更稳妥的用法:把 Claude Code 当辅助,核心逻辑自己过一遍,别全托管。

如果你是"下一个想 AI 重写代码库"的团队负责人:

下次再看到"AI 全自动重构"的宣传,多问几个问题,这几个问题就是我的验收清单:

  1. 测试覆盖率有多少?99.8% 通过是基于多全的测试集?
  2. 迁移后 unsafe(或等价的"逃逸安全检查")比例是多少?比迁移前高还是低?
  3. 这是直译还是重设计?原架构的问题被修了还是被搬运了?
  4. 社区/团队有没有参与设计决策?还是一个人+几十个 Agent 闷头合并?

如果答案都模糊,那就做好当小白鼠的准备。

八、这件事真正的分水岭意义

把情绪和争议放一边,Bun 重写在软件工程史上是个分水岭事件。它证明了一件以前只存在于科幻里的事:

大型代码库(近百万行)的全自动跨语言重写,不再是"能不能"的问题,而是"该不该、如何做好"的问题。

AI 已经能胜任"已知问题域内的确定性转换"——语义不变、边界清晰、测试充分的场景下,它是个近乎完美的翻译器。这类工作包括:

  • 语言 A → 语言 B 的移植(如本例)
  • 老框架 → 新框架的迁移
  • 同构逻辑的批量重写

但它的天花板同样清晰:

  • 它不重设计,只翻译。 原架构的债务照单全收。
  • 测试覆盖不到的地方就是黑箱。 它不会主动发现原有 bug。
  • 它需要人类把关治理与沟通。 Bun 案例的信任危机,恰恰源于跳过了这一环。

所以我的结论是:AI 重写代码库会成为常态,这不一定是坏事——它可以快速清技术债、迁移到更安全的语言、适配新平台。但前提是三件事必须到位:完善的测试覆盖、真实的人类监督、透明的社区沟通。Bun 做到了第一个,跳过了后两个,于是收获了性能提升,也收获了信任危机。

最有意思的一个隐喻:Claude Code 是个 AI 编程助手,而它自己的底层运行时被 AI 重写了——医生给自己开刀,居然还成功了。 但下次轮到给你的项目开刀时,记得先问一句:这里面的每一个 unsafe,到底是经过论证的安全边界,还是"先跑通再说"的甩锅标记?

九、总结

  1. 事件本质:Bun 从 Zig 换到 Rust,不是纯技术选型,而是内存安全诉求、AI 亲和性(Zig 禁 AI 贡献)、以及资本收购后治理权集中,三股力量合流的必然。
  2. 技术真相:这是直译不是重设计。11 天百万行的奇迹背后,是约 13,900 处 unsafe、把 Zig 裸指针问题原样搬进 Rust 的现实。安全的招牌,需要打个折看。
  3. 值得学的干货:SmallVec 避免堆分配、跳过无谓 syscall、惰性初始化 arena——这些系统级性能优化技巧,跨语言通用,是真功夫。
  4. 治理警钟:开源退化成"源码可见",AI 生成代码的版权灰区,供应链高度集中——这些是比"用 Zig 还是 Rust"更该关心的问题。
  5. 给你的建议:生产环境别急着上 canary;用 AI 重写代码库前,先问清楚测试覆盖、unsafe 比例、是否重设计、社区是否参与这四个问题。

工具链会一直变,语言之争也永远吵不完。但作为工程师,我们真正的护城河从来不是"押对了哪门语言",而是看懂引擎盖下面在发生什么的能力——无论那底下写的是 Zig、Rust,还是明年某个还没出生的语言。

推荐文章

Nginx 实操指南:从入门到精通
2024-11-19 04:16:19 +0800 CST
Golang Sync.Once 使用与原理
2024-11-17 03:53:42 +0800 CST
html一个包含iPhoneX和MacBook模拟器
2024-11-19 08:03:47 +0800 CST
liunx宝塔php7.3安装mongodb扩展
2024-11-17 11:56:14 +0800 CST
html夫妻约定
2024-11-19 01:24:21 +0800 CST
Go 单元测试
2024-11-18 19:21:56 +0800 CST
程序员茄子在线接单