Android 13 发布时,AOSP 已包含约 150 万行 Rust;Rust 占新增原生代码约 21%,用于 Keystore2、UWB、DNS-over-HTTP/3 和 Android Virtualization Framework 等组件。这个案例足以说明 Rust 能承担大型生产系统中的实际任务,却不足以支持"新时代的 C"这一称呼。
Rust 与 C 确有相似之处:开发者都能控制内存布局,两者都适合性能敏感的程序,也不依赖垃圾回收器。操作系统、网络组件和嵌入式设备因此成为 Rust 经常出现的领域。但 Rust 官方将它定位为通用编程语言,应用范围还包括命令行工具、网络服务和 WebAssembly,并非只面向底层开发。
两种语言的关键差异,在于问题何时暴露。C 通常把内存管理责任留给开发者;Rust 则借助所有权和借用规则,并由类型系统检查相关约束,让许多问题先在编译阶段出现。它改变的不只是语法,还有开发者与错误打交道的时间。
编译器为什么会成为学习门槛
一段数据由谁管理、一个引用可以存活多久,以及多个线程能否同时修改它,这些问题在 C 中同样存在,只是语言通常不会立即阻止开发者。错误可能到测试、代码审查甚至程序运行后才被发现。
Rust 要求开发者在编译时说明这些关系。初学者常见的困难,是已经清楚程序要做什么,却无法把意图写成编译器认可的形式。复杂数据结构会放大这种负担,异步代码和与 C 接口交互时也尤其明显。
这种约束不意味着软件会自动变得安全。安全 Rust 可以在编译期排除多类内存错误和数据竞争,unsafe 代码、外部 C 接口、逻辑错误及设计缺陷仍需测试、审查和工程治理。Rust 的作用范围,是提前处理其中一部分原本可能留到运行期的风险。
大型工程如何采用 Rust
如果只把从零开始、全部使用 Rust 的软件算作 Rust 项目,就会漏掉大量实际采用。Android 并不是"用 Rust 写成的 Android",但前述组件已经让 Rust 进入大型生产系统。Google 给出的引入路线也很明确:重写数千万行成熟的 C/C++ 代码并不现实,因此重点放在新代码,尤其是需要处理复杂状态或不可信输入的模块。
Firefox 的做法体现了同一类工程现实。它在正式稳定版的构建中使用 Rust,并长期维护 Rust 工具链升级、依赖链接,以及 Rust 与 C++ 的互操作规则。Rust 可以进入复杂且持续交付的软件,但语言之外的工作不会消失:接口划分、统一构建和跨语言维护都会带来成本。
内核开发同样需要区分实验和迁移。用 Rust 编写实验性内核,可以验证内核抽象的设计方式,观察哪些接口能够由类型系统约束,也能探索驱动与资源生命周期的表达方式。重写 Linux 则涉及另一套规模:现有系统的价值还包含硬件架构与驱动支持、ABI、工具链、用户空间兼容性,以及几十年积累的维护成果。更换语言无法直接复制这些内容,重写还可能再次碰到旧系统已经解决的问题。
Linux 内核官方文档采用的是渐进路线:内核主体继续使用 C,同时在 CONFIG_RUST 下支持 Rust,为 Rust 模块提供内核 API、与 C 子系统互操作的设施和相关抽象。Rust 由此进入新模块,在既有系统中逐步验证收益,而不是承担整体替换任务。
面对新增且高风险的系统组件,可以先问一个具体问题:把部分风险提前交给编译器处理,是否值得相应的学习与集成成本。Rust 已经证明自己能够参与大型工程,现有证据尚不足以把它称为 C 的全面继任者。