解构 Rust 话语


Last updated on

金豪东 <hodong@nimfsoft.com>

前言

本书同时分析 Rust 编程语言的技术特性,以及围绕它形成的特定技术与社会话语。这里所说的解构,并不是预先否定某项技术或某种主张,而是把技术事实、语言所提供的保证、工程成本、对因果关系的解释、价值判断和修辞表达彼此分离,再分别检视其依据与适用范围。本书从历史和技术脉络出发,考察 Rust 为实现安全性、性能与并发性而选择的设计,以及这些选择伴随的成本与约束。

本书围绕以下问题展开讨论。

  1. Safe Rust 能防止哪些种类的内存错误和数据竞争?在面对 unsafe、外部函数接口(FFI)、逻辑错误与运行故障时,这些保证的有效范围到哪里为止?
  2. 与 C++、基于垃圾收集器(GC)1 的语言、Ada 和 SPARK 的方法相比,Rust 的所有权、借用、生命周期、类型系统和零成本抽象具有什么优势与权衡?
  3. 企业和开源项目的采用案例及量化成果,在多大范围内能够证明 Rust 本身的效果?又该如何把这种效果与架构、算法、运行时、硬件和组织变化的效果区分开来?
  4. 对现有系统进行重构、渐进式现代化、选择性替换高风险组件以及全面重写,应在什么条件下加以区分和组合?
  5. 当有条件成立的技术优势被转换为适用于所有系统的普遍优越性,或被转换为对开发者智力与资格的判断时,会发生哪些逻辑跳跃?
  6. 声称某种语言是“唯一替代方案”时,预设了哪些需求和候选集合?如果省略这些前提与比较过程,会产生哪些逻辑错误?

为回答这些问题,本书优先采用语言规范与标准、官方项目文档、政府报告、CVE 记录、企业原始技术报告和同行评审研究等一手资料。审查量化主张时,会确认研究对象与样本、分子与分母、基线、工作负载、软硬件环境以及比较期间;并区分观测结果、统计估计、因果归因和作者解释,尽可能对成功与失败案例采用相同的证据标准。当资料只涉及特定组织或系统时,本书不会超出其范围作一般化推论,并同时说明不确定性与替代解释。

比较对象包括 C++、Java、C#、Go、Ada 和 SPARK。比较的目的不是把某种语言排列为另一种语言的简单替代品,而是考察不同语言与生态系统如何在性能、内存控制、开发生产力、可验证性、实时性、工具以及长期可维护性之间选择成本。Ada 和 SPARK 展示了另一种不依赖 GC 而追求安全性与可靠性的历史路径,也构成重要的比较对象。本书还把语言特性与变更策略分开,不把保留或废弃现有系统视为二选一,而是将重构、现代化、局部替换和重写评价为彼此独立的工程手段。

本书所说的Rust 话语,并不代表 Rust 基金会、核心开发团队或整个社区的官方立场。Rust 项目的官方渠道一直公开讨论并改善编译时间、异步编程、工具和安全边界等多方面课题。本书分析的是在部分公开技术论坛和社交媒体上反复观察到的特定论证方式。这些网络案例不是用于证明此类主张在整个社区中出现频率的统计样本,而是作为分析主张结构与话语功能的定性材料。

Rust 在不依赖 GC 的情况下结合了强有力的内存安全保证与高度控制能力,并在产业和开源项目中取得了重要成果。本书并非为了缩小这些成果,也不是为了推荐某种特定技术选择。其目的在于用同一标准检视优点与局限、保证与成本、观测与解释。因此,本书的结论也不是最终宣言,而是依据目前可确认的证据作出的判断;当出现更好的资料或反例时,结论可以修正。


知识共享许可协议 本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。


目录


第一部分:Rust 的出现与技术特性

第一部分分析 Rust 编程语言如何应对系统编程领域的课题,以及人们通过哪些特性讨论它。

第一章考察 Rust 诞生背景中的性能与安全权衡,并介绍为此采用的主要技术特性,包括所有权模型、零成本抽象(ZCA)理念,以及以 Cargo 为代表的生态系统。

第二章分析这些技术基础如何与开发者体验(DX)、叙事和机构支持相互作用,并通过复杂因素影响采用。

1. Rust 语言简介及主要特性

本章并不只是罗列 Rust 的特性,而是检视用于分析内存安全保证边界以及设计优点与权衡的两个问题。第一,Rust 试图在系统编程中解决哪些缺陷与成本?第二,所有权、借用、生命周期、类型系统与零成本抽象所提供的保证延伸到哪里,又伴随哪些权衡?

为此,本章区分语言的设计目标、规范层面的保证、编译器与库的实现,以及在实际工作负载中观察到的结果。内容将依次考察所有权与借用、零成本抽象、类型与模式匹配、Cargo 生态系统,但不会把某项设计目标扩大为关于所有程序性能或安全性的普遍结论。工业采用成果与变更策略将在后续章节中按照独立的证据标准处理。

1.1 诞生背景:性能与安全的权衡

系统编程可能同时要求硬件控制、可预测的资源管理、吞吐量与延迟、内存安全,以及并发错误防止。不过,如果简单地把这些要求表述为“性能还是安全”的二选一,就会过度缩减历史上存在的选择。C 与 C++ 围绕低层控制和手动资源管理发展;Ada 与 SPARK 将强类型、运行时检查、契约与形式化验证结合起来;基于 GC 的语言则使用自动内存回收和托管运行时。哪种方法合适,取决于缺陷模型、实时性要求、工作负载、运行环境与验证要求。

Rust 起源于 Mozilla Research,并发展为一种同时追求内存安全、并发性、低层控制与性能的系统编程语言。2 “无需 GC 即可提供内存安全,并以能够与 C++ 竞争的性能为目标”是一项设计目标与价值主张,而不是保证每个 Rust 程序都与每个 C++ 程序具有相同性能,也不是保证运行时成本与失败会消失。因此,下面三个目标也必须在区分设计目标、语言保证、实现特性与观察结果的前提下理解。

安全性

Safe Rust 通过所有权、借用与类型规则防止某些无效内存访问和数据竞争。这项保证以编译器与库、使用 unsafe 实现的抽象以及 FFI 边界分别遵守其契约为前提。3 它不会自动保证不存在 panic、死锁、资源泄漏或耗尽、逻辑错误、所有安全漏洞,或服务连续性中断。第 1.2 节与第 3.2 节将具体检视准确的保证边界。

性能

Rust 无需强制垃圾收集器即可生成本机代码,并采用零成本抽象原则:高级抽象的设计不应要求可避免的额外运行时开销。4 这一原则并不表示每种抽象始终具有相同速度,也不表示编译时间、二进制大小、内存使用、调试难度与开发者认知成本为零。实际性能必须在明确说明工作负载、算法、优化、分配、I/O、库与硬件条件后进行测量。

并发性

Safe Rust 的所有权与类型系统可以防止数据竞争,但不会消除一般竞态条件、死锁、饥饿、优先级反转或分布式系统的一致性问题。5 因此,“无畏并发”应当被理解为范围明确的表述:编译阶段会阻止某些内存安全违规和数据竞争,而不是所有并发缺陷都不存在。

本章的重要出发点,是区分 Rust 在一种设计中同时追求安全性、性能和并发性这一事实,与这些目标并不等于所有环境中的观察结果。接下来的各节将依次检视所有权与借用提供的具体保证、被拒绝的有效程序、运行时检查与实现依赖,以及与其他设计之间的权衡。

1.2 通过所有权、借用和生命周期管理内存

本节不把所有权当作一句口号,而是将其分为三个层次加以考察。所有权表示清理值与资源的责任,借用在不转移所有权的情况下限制访问权限,生命周期则描述引用不得比其所指向的值使用得更久这一关系。这三个层次彼此关联,但并不是同一个概念。6

1. 所有权:清理值与资源的责任

在 Rust 中,每个值都有所有者,所有权可以通过赋值或函数调用发生移动。值被移动之后,编译器会拒绝通过原变量再次使用它。不过,整数等实现了 Copy 的值会在赋值时被复制,因此原变量仍可继续使用。所以,“所有赋值都是移动”并不是准确的说明。

所有者离开有效作用域时,值会按照 Drop 进行清理。拥有堆分配的类型可以在此时释放该分配,文件、套接字和锁等资源也可以与类型的析构过程绑定。这一规则是在 Safe Rust 中防止二次释放和释放后使用等错误的基础,但并不表示析构函数在所有终止路径上都必然执行。进程被强制终止或 abort、故意泄漏以及引用计数环等情况下,资源可能不会立即回收。

2. 借用:区别于所有权的访问权限

引用并不拥有其目标。共享引用 &T 在有效期间提供读取访问,可变引用 &mut T 则表示该期间内的排他访问。通常可以概括为“多个共享引用或一个可变引用”,但关键在于限制引用实际使用期间别名与修改同时发生。6

这些规则会在 Safe Rust 中阻止未经同步的并发读写所产生的数据竞争。不过,它们不会消除结果取决于执行顺序的一般竞态条件、死锁、饥饿或优先级反转。基于 UnsafeCell 的内部可变性、原始指针和 unsafe 代码还需要安全的外部接口维护额外的不变量。

3. 生命周期:引用有效性的关系

生命周期不是直接控制值何时销毁的运行时机制,而是描述引用之间必须满足何种有效期关系的静态契约。生命周期标注不会让引用存活得更久;它只是描述函数所接收与返回的引用之间的关系等信息,使编译器能够进行检查。6

当前借用检查器使用非词法生命周期(NLL),考虑引用的最后使用位置,而不只是所在代码块的末尾。尽管如此,静态分析无法完整判定所有会终止程序的语义,因此必然具有保守性,并会拒绝一些实际执行时安全的程序。Rust 项目将 Polonius alpha 的稳定化列为 2026 年目标,其中一个原因就是要接受更多当前分析无法表达的有效模式,包括条件借用和 lending iterator。7

4. Safe Rust 保证的前提与边界

Safe Rust 的核心保证,是安全代码本身不能引发未定义行为这一健全性(soundness)性质。不过,这项保证以编译器、标准库与第三方库、分配器、使用 unsafe 实现的抽象、操作系统接口及 FFI 代码分别遵守各自契约为前提。unsafe 并不是允许未定义行为的标记,而是表示实现者必须自行验证编译器无法检查的义务。3

因此,所有权与借用能够阻止悬垂引用、无效别名、二次释放和数据竞争等重要错误类别,但不会消除内存不足、资源耗尽、panic、abort、逻辑错误、死锁、外部代码违反契约或编译器缺陷。若 FFI 边界的 C 代码引发未定义行为,其影响可能扩展到包括 Rust 部分在内的整个程序。

5. 基本规则之外的所有权模式及其成本

现实中的数据结构有时很难仅凭单一所有权与静态借用来表达。Rust 因此提供一些类型,在保持安全抽象的同时改变检查时机或同步方式。8

  • Rc<T> 在单线程中表示多个所有者,但需要堆分配以及引用计数的增减;强引用形成环时可能造成内存泄漏。
  • RefCell<T> 提供内部可变性,并在运行时而不是编译时检查借用规则。违反规则时会发生 panic 而不是未定义行为,但会增加状态跟踪与分支成本。
  • Arc<T> 使用原子引用计数实现跨线程共享。由于原子操作本身有成本,在不需要线程安全时可能不如 Rc<T>
  • Mutex<T> 只向已获取锁的代码授予内部值的可变访问。类型与 RAII 会结构化锁的释放,但获取锁、锁竞争的成本以及死锁可能性仍然存在。

这些类型并没有移除所有权规则。它们把静态检查难以表达的模式封装在安全 API 后面,同时选择运行时检查、堆分配、引用计数、原子操作与锁作为成本,并引入新的失败条件。

阶段性结论

从内存安全保证的边界来看,所有权、借用与生命周期在健全的 Safe Rust 边界内,会有力阻止特定的悬垂引用、二次释放、释放后使用、无效别名和数据竞争。不过,这项保证依赖 unsafe 实现与外部边界的契约,并不涵盖所有错误或运行故障。

从设计优点与成本来看,这种设计无需运行时垃圾收集器便可提供强静态保证,但要求通过类型和接口显式表达所有权关系,也可能拒绝部分有效程序。选择共享所有权或内部可变性时,静态成本并不会消失,而是转移为引用计数、运行时检查、原子操作和锁的成本。因此,与其把 Rust 的内存管理模型理解为“没有成本的安全”,不如把它评价为一种静态阻止特定错误、并在必要时通过类型显式选择替代成本的设计。

1.3 零成本抽象的谱系

零成本抽象并不是声称程序中的所有成本都为零,而是一项用于设计语言和库的原则。它要求未使用的功能不应产生时间或空间成本,并使实际使用的抽象能够与合理手写的低层实现竞争。这一原则在 C++ 的 zero-overhead principle 中得到系统表达,Rust 则把它作为同时追求内存安全与低层控制的一条设计轴线。9

C 的 struct、宏、inlinesizeof 等参与编译阶段或提供低层控制的功能影响了这段历史。不过,如果把所有编译时技术都称为零成本抽象的早期形式,概念范围就会过于宽泛。本节区分低层实现技术语言层面的抽象原则以及特定编译器生成的观测结果

1. 静态分派与单态化

实际使用的泛型函数和静态分派的 trait 会针对具体类型进行单态化(monomorphization)。这种方式在编译时确定调用目标,为直接调用、内联等优化创造机会。由于优化器可以同时看到具体类型与操作,抽象边界有时会从最终机器码中消失。9

不过,单态化并不保证“始终生成相同机器码”,也不保证“始终比手写代码更快”。生成结果可能随 rustc 与 LLVM 版本、优化级别、crate 边界、LTO、代码生成单元、目标 CPU 与启用的功能以及周边代码而变化。同一份源代码在开发构建和发布构建中可能得到截然不同的优化结果。10

2. 动态分派、分配与运行时检查

Rust 并非所有抽象都会在静态阶段被消除。dyn Trait 使用数据指针与虚方法表(vtable),在运行时选择调用目标。这会产生间接调用成本,并通常减少内联机会;但由于无需为每个具体类型复制一份代码,也可能减小代码体积。11

动态分派与堆分配也不是同一个概念。&dyn Trait 可以借用已有值,本身不要求堆分配;Box<dyn Trait> 则选择了基于 Box 的堆所有权表示。VecString 的分配和重新分配,以及 Box 的堆所有权,是所选数据结构的行为,不会因为被称为“抽象”就消失。数组与切片的安全索引在越界时还具有触发 panic 的语义;边界检查能否被消除是优化结果,而不是语言的普遍保证。11

3. 减少运行时开销时可能产生的成本

单态化会为具体类型生成机器码,因此可能有利于执行性能和内联,但也可能增加编译时间与二进制体积。代码体积增大还可能提高指令缓存压力,不过实际影响取决于调用频率、代码布局、目标处理器和工作负载。相反,动态分派会保留间接调用,却能减少代码重复。10

构建设置同样存在权衡。较高的优化级别与 LTO 能提供更多优化机会,但可能增加编译和链接时间;优化后的代码还可能因源代码顺序与执行状态被重排而更难调试。增加代码生成单元可以加快并行编译,却可能降低生成代码的性能。可维护性也必须同时评估抽象减少的代码重复,以及泛型 API、错误诊断和构建追踪带来的复杂度。因此,编译时间、二进制体积、指令缓存、调试与维护成本,是不同于运行时吞吐量的独立评价维度。10

4. 迭代器示例的保证范围

// 计算 1 到 99 中所有 3 的倍数的平方之和
let sum = (1..100).filter(|&x| x % 3 == 0).map(|x| x * x).sum::<u32>();

这段代码组合 filtermapsum,以声明式方式表达计算。在优化构建中,适配器调用可能被内联,中间状态可能被消除,从而生成近似单个循环的代码。然而,仅凭这一示例不能断定所有迭代器链都与手写循环具有相同性能或机器码。Rust 官方书籍中的比较也只是观察到循环与迭代器在一个搜索工作负载中结果相近,并不是跨越不同输入和条件的全面等价证明。12

5. 比较性能主张所需的条件

有关零成本抽象的性能比较,至少应明确以下条件。

  • rustc、Cargo 与主要 crate 的版本
  • 目标三元组、CPU、启用的指令集功能与操作系统
  • 开发、发布或自定义 profile,以及优化级别、LTO、代码生成单元和 panic 策略
  • 输入数据、工作负载、迭代次数、预热过程与测量方法
  • 作为比较基线的循环或其他实现所使用的算法、分配与 I/O 条件
  • 除延迟与吞吐量外,还包括编译时间、二进制体积与内存使用量

这些条件不同时,同一种语法抽象也可能产生不同结果。因此,不能把一个基准测试中的优势推广为整门语言或所有抽象的固定属性。

阶段性结论

从设计优点与成本来看,静态分派与单态化是把高级接口降低为可以直接调用和优化的具体代码的有力机制。不过,零成本抽象原则并不是一项规范级保证,不能保证每种抽象都产生相同机器码或性能。动态分派、堆分配、边界检查以及库的运行时行为,会随着所选表示和数据结构继续存在。

与其说 Rust 消除了成本,不如说它提供了一种选择在何处支付何种成本的设计。避免运行时间接调用,可能需要承担单态化带来的编译时间与代码体积成本;减少代码重复,则可能选择动态分派成本。因此,对零成本抽象的评价不应停留在口号上,而应同时比较具体工作负载、构建条件、生成代码与整个生命周期成本。

1.4 通过类型系统与模式匹配确保安全

Rust 的静态类型系统限制值的表示方式以及允许对其执行的操作。程序可以把数据可能处于的状态记录到类型中,编译器则能在编译时拒绝与该类型不一致的操作。不过,类型检查器保证的是类型中已经表达的条件,并不意味着业务规则、外部环境和所有执行结果都会自动正确。

1. OptionResult:显式表达状态的范围

Rust 的枚举是各变体可以包含不同数据的和类型。Option<T>Some(T)None 表示值的存在或缺失,Result<T, E>Ok(T)Err(E) 表示成功和失败。API 使用这些类型时,调用者可以从类型中看到缺失或失败的可能路径,并选择传播或分支处理。13

不能把这一优点扩大为“Rust 中不存在 null 或异常”的普遍命题。安全引用 &T&mut T 以及 Box<T> 以指向有效值的非空指针为前提,但原始指针可以为空,FFI 与操作系统接口也可能传递空指针、错误码和外部异常。Option 不会自动净化这些边界;它只是把经过验证的缺失可能性表达为 Rust 类型的手段。13

未使用的 Result#[must_use] 约束,但它默认属于 lint。可以降低 lint 级别,也可以用 let _ = 明确丢弃,因此编译器并不会为每个错误强制一种有意义的恢复策略。? 运算符通常也不是处理错误,而是把错误传播给当前函数的调用者。记录、重试、使用替代值还是终止,仍然属于 API 与应用程序设计问题。13

2. 模式匹配与穷尽性检查所保证的内容

match 会检查各分支合在一起是否覆盖目标类型当前可以构造的所有值。删除下面代码中的 None 分支会导致编译失败。

fn describe(value: Option<i32>) -> &'static str {
    match value {
        Some(number) if number > 0 => "正数",
        Some(_) => "零或负数",
        None => "没有值",
    }
}

这一保证同样有边界。14

  • 通配分支 _ 覆盖其余所有值,因此可以通过穷尽性检查,但它不会表明哪些变体得到了有意处理。API 新增变体时,现有通配分支可能静默吸收它。
  • 模式守卫的条件可能为假,因此不能证明该模式匹配的所有值都已处理。上例中,Some(number) if number > 0 后仍需另一个 Some 分支,原因就在这里。
  • if letlet ... elsewhile letmatches! 用于只关注部分模式,并不要求处理所有情况。
  • 来自其他 crate 的 #[non_exhaustive] 枚举要求通配分支,以便未来增加变体。这有利于 API 演进,但也削弱了调用者通过列举当前全部变体、让新状态触发编译错误的能力。

因此,穷尽性检查保证的是:“根据当前类型定义和已写出的模式,没有遗漏情况。”它不证明每个分支的行为正确,也不证明通配分支会适当地处理新状态,或外部状态与类型定义一致。

3. 只有把不变式表达进类型,才能阻止无效状态

枚举、newtype、私有字段和经过验证的构造函数,可以让某些无效状态难以表达。例如,可以把经过范围验证的标识符或状态转换建模为单独类型,使使用安全公共 API 的代码无法绕过验证。

但开始时间必须早于结束时间、多个字段之间保持一致、文件实际存在、权限策略正确以及网络响应可信等关系,并不会只因类型名称而产生。必须把这些条件实现为构造函数和方法的不变式,并控制字段可见性和转换路径。一个值即使结构上类型正确,业务含义仍可能错误。

这一边界在 unsafe、FFI、反序列化和外部输入处尤其重要。把无效的枚举判别值或无效引用当作 Rust 值使用,可能导致未定义行为。外部字节、C 结构体、数据库行与网络消息,在作为 Rust 类型处理之前,必须验证长度、范围、编码、判别值以及字段间关系。类型系统的保证从有效类型值已经构造之后开始,并不会替代在边界建立该前提的责任。15

4. 运行时失败与控制流成本

OptionResult 把失败表示为值,并不意味着运行时失败消失。unwrapexpect 遇到非预期变体时会 panic,并根据构建的 panic 策略展开栈或中止进程。unwrap_unchecked 省去检查,但在错误变体上使用会触发未定义行为。16

按状态分支的代码会形成真实控制流。编译器可能把简单的 match 降低为条件分支、跳转表、条件移动或无分支代码,但具体结果取决于变体数量、数据布局、优化级别、目标 CPU 与周围代码。模式匹配或组合子本身并没有零成本保证。对高频路径,需要测量分支预测和错误值构造成本;把大型错误变体直接放入枚举,还是通过 Box 等方式间接存放,也是表示大小与分配成本之间的选择。

5. 表示方式、API 演进与维护成本

默认 repr(Rust) 枚举的确切字段顺序、判别值位置与整体大小,通常不是稳定 ABI。Option<&T> 等官方文档保证空指针优化的特定类型属于例外,但不能把一个案例的体积优化推广到所有 Option<T>Result<T, E> 与用户枚举。若 FFI 或存储格式依赖布局,就需要合适的 repr 与单独的兼容性设计。16

把状态精细地划分为类型,可以让遗漏变成编译错误,并明确代码审查与测试目标。另一方面,变体和错误类型越多,match 分支、转换代码、文档与测试也会增加;通用错误层次和较长的组合子链可能使调试路径更复杂。给公共枚举增加变体可能破坏下游代码的穷尽匹配;#[non_exhaustive] 与通配符提高兼容性,却会削弱自动发现新状态的能力。类型精度、API 稳定性、诊断清晰度与维护成本必须一起设计。

阶段性结论

把视野从内存安全边界扩大后可以看到,OptionResult 与穷尽模式匹配,能够在缺失、失败和状态分支已表达为类型的代码中,于编译时阻止重要遗漏。但它们不会消除原始指针与 FFI 中的空值、panic、被忽略的错误、被通配分支吸收的新变体、错误业务规则和无效外部输入。能够阻止无效状态的范围,取决于不变式在类型与安全 API 中表达得多准确,以及它们是否在每个边界都得到保持。

从设计优点与成本来看,用类型细分状态,是把运行时的隐式失败转移到显式接口和编译器诊断中的有力机制。代价可能包括 API 设计、分支与表示大小、错误转换、兼容性、调试和维护成本。因此,类型系统与模式匹配的价值不在于“消除所有错误”,而在于明确选择要表达哪些错误状态,以及在哪些边界验证它们。

1.5 生态系统:Cargo 与 Crates.io

编程语言的使用体验并不只由语法和类型系统决定。用于创建项目、选择依赖、构建、测试、部署并长期更新的工具和生态系统,同样会影响开发成本与失败可能性。在 Rust 中,Cargo 是官方包管理器兼构建工具,crates.io 是默认的公共包注册表。本节把二者作为 区别于语言层安全保证的工具与生态系统层 进行分析。

1. Cargo 所标准化的工作流及其范围

Cargo 以 Cargo.toml 为中心声明包元数据与依赖,并提供 cargo newcargo buildcargo checkcargo testcargo doccargo packagecargo publish 等共同入口。相较于直接调用 rustc 并组合各项目自己的 shell 命令,由一个工具协调依赖下载与编译顺序、约定的目录结构和构建 profile,有助于减少开发环境之间的差异,也更容易形成自动化、CI 与文档化的共同实践。17

但是,共同工作流由语言保证的程序性质,以及 在不同环境中生成相同产物的可复现构建 是不同概念。即使 Cargo 选择了相同的依赖版本,最终结果仍可能受到 rustc 与 Cargo 版本、目标三元组、构建 profile 与标志、环境变量、构建脚本、过程宏、原生库和外部工具的影响。因此,仅仅存在统一的 cargo build 命令,并不能保证内存安全、功能正确性或逐比特可复现性。

2. 依赖解析、Cargo.lock、feature 统一、SemVer 与 MSRV

Cargo 的 resolver 会计算满足各个包所声明版本要求的依赖图,并在使用锁文件时把结果记录到 Cargo.lock。锁文件存在时,Cargo 会优先采用其中记录的版本,从而使依赖选择更稳定。--locked 会在必须修改锁文件时直接报错,--frozen 则把这一限制与离线运行结合起来。不过,--offline 只能使用本地已经存在的包,因此依赖解析结果也可能与在线状态不同。换言之,锁文件能显著提高依赖选择的确定性,却并不会固定网络与缓存状态,也不会冻结整个构建环境。18

锁文件的作用还会随着包的角色而变化。对于最终应用程序,它有助于固定一组已经验证过的依赖;但当一个库被其他项目使用时,依赖会依据使用方的 Cargo.toml 和完整依赖图重新解析。Cargo 官方 FAQ 也明确提醒,库自身的 Cargo.lock 并不能控制使用方最终选择哪些依赖。18

resolver 会尽可能复用同一包的同一版本,但版本要求冲突时,同一个 crate 的多个版本可能同时出现在一张依赖图中。这会增加重复编译和代码体积,而且由不同版本定义的同名类型,在运行时类型识别或公共 API 边界上可能彼此不兼容。cargo tree -d 可用于查找这些重复版本。18

feature 也不是彼此完全独立的简单开关。当多个包共享同一个依赖时,默认原则是采用所有已启用 feature 的并集。resolver version 2 会在目标特定依赖、构建依赖与过程宏、开发依赖等部分情况下减少不必要的 feature 统一。因此,哪些 workspace 成员一起构建、选择哪些目标和 feature,都可能改变实际编译图及其成本。18

Cargo 在选择版本时以 SemVer 兼容性为前提,但官方兼容性指南本身也说明,它并不是强制所有项目遵守的规则。语法上兼容的改动同样可能影响运行结果。rust-version 可以表达包所支持的最低 Rust 版本(MSRV),并让 resolver 在版本选择时考虑这一信息,但它是可选元数据,也可以通过 --ignore-rust-version 绕过。因此,SemVer 与 MSRV 是管理升级风险的约定和工具,而不是新版本必然兼容、绝无回归的证明。18

3. 构建过程中执行的代码,以及原生依赖与目标依赖

Cargo 的依赖并不一定只是把 Rust 源文件交给 rustc。包的 build.rs 会在构建该包之前执行,可以编译 C 库、查找系统库、生成源代码,或者执行针对不同平台的配置。Cargo 文档说明,构建脚本在运行时可以执行任意工作。19

过程宏(proc macro)也会在编译时作为实际代码执行。根据 Rust Reference,过程宏可以使用编译器拥有的资源,例如文件访问,并具有与 Cargo 构建脚本同类的安全考虑。因此,不受信任依赖中的构建脚本和过程宏应被视为 构建时代码执行边界。使用 Safe Rust 语法编写的应用代码所享有的内存安全保证,与构建过程中执行第三方代码时所承担的信任问题,并不是同一层面的性质。19

原生依赖还会引入独立的环境前提。构建脚本可以通过 links 元数据和链接器指令连接 C/C++ 库等原生库,目标特定依赖也可能随着操作系统和体系结构而变化。交叉编译时,构建依赖在宿主机上执行,而最终 crate 可以面向另一个目标编译。因此,即使使用相同的 Cargo.lock,只要宿主工具、链接器、系统库或目标 SDK 不同,构建结果乃至能否成功构建都可能发生变化。19

因此,如果需要长期保存或高保证构建,除了锁文件,还应记录并控制工具链版本、目标、profile 与标志、原生工具和库、必要环境变量,以及构建时代码的执行条件。

4. crates.io 提供的完整性与分发功能,以及供应链保证的边界

crates.io 是 Cargo 默认的公共注册表,为包的发现和分发提供共同路径。注册表索引记录每个已发布 .crate 文件的 SHA-256 校验和,Cargo 会验证下载数据是否与该校验和一致。这是重要的完整性机制,用于确认经过传输或缓存后取得的所选包字节与注册表元数据一致。20

已发布版本的管理方式也考虑了稳定性。crates.io 的目标是永久保留已发布版本;有问题的版本可以被 yank,而不是删除。被 yank 的版本通常不会再被新的依赖解析选中,但如果已经写入现有 Cargo.lock,仍可继续使用。所有者可以管理发布新版本和 yank 既有版本的权限;发布元数据还要求提供许可证表达式或许可证文件,标准许可证可用 SPDX 表达式记录。20

这些功能不能被扩大解释为整个供应链的安全保证。校验和验证的是 注册表中记录的包字节是否一致;它不会证明代码设计是否安全、它与公开仓库中的哪个特定提交或何种审查流程相对应,也不会证明维护者会长期继续维护。即使存在许可证元数据,整个传递依赖图的许可证是否符合项目政策与法律要求,仍需要单独审查。yank 也不会自动移除或修复已经存在于锁文件中的版本。

因此,crates.io 的可访问性与集中式分发路径、包校验和、所有权和 yank 功能都很有价值,但 可发现性、分发完整性与权限管理,和 代码来源验证、安全性、维护质量与长期支持 是不同的评价项目。

5. 网络、缓存、vendoring、审计与更新的生命周期成本

Cargo 会下载注册表依赖和 Git 依赖,并缓存到 $CARGO_HOME 等位置。缓存可以减少重复构建时的网络与处理成本,但在新环境或空缓存中仍需要重新访问网络并下载。可以先用 cargo fetch 取得依赖,再使用 --offline--frozencargo vendor 还可以把 crates.io 与 Git 依赖的源代码复制到由项目管理的本地目录。不过,vendoring 并不会消除外部依赖,而是选择 把保存、同步与更新责任转移到项目内部21

依赖图越大,需要下载的数据与缓存空间、编译工作、重复版本与启用的 feature、构建脚本和过程宏的执行范围,以及需要审查的许可证、漏洞和维护状态都可能随之增加。Cargo 文档也建议,在增加构建依赖时考虑编译时间、许可证和维护方面的影响。尤其在宿主与目标不同的交叉构建中,同一个依赖可能因为承担不同角色而被再次编译。19

cargo update 会有意更新锁文件中选定的版本。因此,更新不只是取得更大的版本号,而是一项维护工作,需要同时审查变更记录、测试、SemVer 前提、MSRV、安全通告与回滚能力。RustSec 的 cargo audit 会把 Cargo.lock 与已知安全通告数据库进行比对,但它不能证明不存在尚未报告的漏洞或设计缺陷。自动化审计可以辅助供应链审查,却不能保证审查本身已不再必要。21

与 C、C++ 生态系统比较时,也应使用对称标准。说“C/C++ 没有包管理器或标准化构建实践”并不准确。可以使用 CMake、Meson 等构建系统,vcpkg、Conan 等 C/C++ 包管理器,以及操作系统自己的包管理器。真正的差异与其说在于工具是否存在,不如说 Rust 把 Cargo 与 crates.io 放在官方工作流中心,从创建项目到依赖解析、构建、测试、发布都提供了强而统一的默认路径。另一方面,C/C++ 更丰富的工具选择可能提高集成成本,却也能提供适应既有构建体系、系统包、二进制打包和组织内部仓库政策的选择。21

中间结论

Cargo 与 crates.io 是 Rust 重要的工程优势。共同的 manifest 与命令体系、依赖 resolver 与锁文件,以及带校验和的默认注册表,使项目配置与依赖选择更明确,也更容易自动化。尤其是把已经验证过的 Cargo.lock 与固定的构建条件一起管理,可以更容易地在不同时间和开发环境中复用同一组依赖。

但这些优势并不等同于语言层的安全保证。锁文件不会固定整个构建环境或第三方代码的可信度,校验和不会审查代码质量,SemVer、MSRV、yank 和安全通告也不会替项目作出维护决定。便于组合小型依赖这一便利性,也可能同时带来传递依赖、构建时代码执行、网络与缓存、编译时间、许可证与漏洞审计、更新和长期支持方面的成本。

因此,在大规模、长期运行或高保证环境中,不应仅凭“使用 Cargo”或“crates.io 生态系统很大”就判断工具体系的优劣,而应一起评估实际的传递依赖图与启用的 feature、目标、构建脚本和过程宏、原生依赖、离线恢复与 vendoring 策略,以及审计、更新与回滚流程。Cargo 为一致地完成这些工作提供了强有力的基础,但并不会消除供应链和生命周期责任本身。

1.6 结论:保证边界与设计成本

本章的第一个问题是,Rust 试图在系统编程中减少哪些缺陷与成本。前文分析所确认的核心是:Safe Rust 通过所有权、借用与类型规则,在编译阶段强力阻止悬垂引用、释放后使用、二次释放、不合法别名和数据竞争等重要类别的问题;OptionResult 与穷尽模式匹配则可以把缺失、失败和状态分支转移到显式的类型与控制流中。Cargo 与 crates.io 也提供工具层面的优势,把项目配置、依赖解析、构建、测试与发布组织为共同的工作流程。不过,这三个层面的性质与保证并不相同。

第二个问题是,这些设计能够保证到什么范围,以及会带来哪些权衡。Safe Rust 的内存安全建立在这样一个前提上:编译器与库、使用 unsafe 实现的抽象以及 FFI 边界都遵守各自的契约;它并不保证不会发生 panic、一般竞争条件、死锁、内存或资源泄漏与耗尽、逻辑错误,也不保证服务连续性。用类型显式表示状态的方式,同样只有在不变式确实被表达在类型和安全 API 中,并且在外部输入、FFI 等边界上验证了这些前提时,才能阻止相应类别的错误。状态建模越细,还需要同时承担 API 演进与兼容性、错误转换、调试和维护成本。因此,不能把内存安全或类型层面的保证等同于系统整体的正确性、可用性与可靠性。

在性能方面,零成本抽象也不是普遍的速度保证,而是减少可避免运行时开销的一项设计原则。静态分派和单态化可以减少运行时调用成本并创造优化机会,但也可能增加编译时间、代码体积和调试成本;动态分派、堆分配、边界检查以及库的运行时行为,则可能根据所选择的表达方式继续存在。因此,评估时不仅应考虑吞吐量和延迟,还应在实际工作负载与构建条件下同时考察编译时间、二进制大小、内存使用、调试与维护成本。

工具与生态系统也存在同样的边界。Cargo 的共同工作流程、Cargo.lock、crates.io 的校验和与分发功能可以使依赖选择和自动化更加结构化,但它们并不保证整个构建环境的可复现性,也不替代对第三方代码质量、安全性与长期维护的保证。在大规模、长期运行环境中,还需要管理 toolchain 固定与更新、构建脚本与过程宏、原生依赖、网络与缓存及离线恢复、供应链、许可证与漏洞审计、更新与回滚,以及与既有代码和构建体系集成、迁移的成本。由于 C 和 C++ 同样存在实际的构建与包管理工具,比较的关键并不是有没有工具,而是共同默认路径的整合程度与适配既有资产的选择空间之间的权衡。

因此,在不适合或不希望设置运行时 GC、同时需要底层控制,并且重视尽可能早地阻止部分内存生命周期、别名关系和状态遗漏错误的环境中,Rust 可以成为有力的选择。反过来,如果为了处理静态规则拒绝的有效模式而频繁需要共享所有权、运行时检查与同步,或者编译时间、代码体积、FFI、原生依赖、既有工具与迁移成本成为主导因素,权衡关系就会发生变化。这既不意味着其他方法总是更好,也不意味着 Rust 总是更好。

第 1 章的结论是,Rust 的核心价值与其说在于消除成本,不如说在于通过编译阶段以及显式类型和接口更强地控制特定错误,同时改变部分成本与责任所在的位置。只有区分语言保证、实现与运行时行为、工具与生态系统的便利性,以及实际项目中观察到的结果,才能准确评估这些优势与成本。下一章将把这些有条件的技术优势与工具特性在多大程度上实际促成采用决策,作为一个独立的经验性与因果性问题来讨论。

2. Rust 的采用因素:技术、生态系统与叙事的互动

必须区分“某种语言实际被使用”这一观察与“为什么被采用”这一因果解释。某个组织或项目使用了 Rust,说明在那些条件下采用 Rust 是可行的,但这并不意味着语言本身是该决策的唯一原因,也不意味着同样的效果会在其他组织中重现。此外,本书所说的“采用”可能包括试验性使用、引入到新组件、对既有系统进行部分替换、组织级标准化等不同范围,因此不会把任何资料的结论推广到其实际能够证明的范围之外。

本章把有关 Rust 采用的解释分为技术适配性、开发者体验与工具、机构与生态系统条件,以及叙事与公众认知来分别考察。这些因素可能相互影响,但某一因素的存在本身不能证明另一因素的效果,也不能证明整体采用的原因。因此,技术优势、工具便利性、机构支持与话语效果将被视为彼此独立的证据问题。

2.1 技术背景:内存安全与性能目标

在关于 Rust 采用的技术解释中,一个常见主张是:Rust 以不依赖运行时垃圾收集器(GC)而加强内存安全为目标,同时追求底层控制能力与较高执行性能,从而为系统软件提供了新的选择。Rust 官方文档说明,所有权规则由编译器检查,并且这一模型被设计为在 Safe Rust 的范围内无需 GC 即可提供内存安全保证。借用规则通过限制同时存在的可变引用,有助于在编译阶段阻止数据竞争;Rust Reference 则把数据竞争、通过生命周期已结束或未正确对齐的指针进行访问、创建无效类型值等归类为未定义行为。22

这里必须区分设计目标观察到的性能结果。所有权规则本身不要求单独的运行时 GC,并不保证所有 Rust 程序都比 C 或 C++ 程序更快或具有相同性能。正如第 1.3 节所讨论的,实际性能取决于算法、分配、边界检查、分派、库与编译器实现、目标硬件和工作负载。

尤其把现代 C++ 简单表述为“没有安全机制的手动内存管理语言”并不准确。现代 C++ 存在 RAII、智能指针、容器与 span 等用于更安全地管理资源和生命周期的语言与库实践,C++ Core Guidelines 也建议避免原始所有权指针以及直接使用 new/delete,转而通过资源句柄进行自动管理。不过,这些实践与分析工具的使用,与 Safe Rust 默认由编译器检查所有权和借用规则的方式,在保证所在的层次上并不相同。23

不能把所有基于 GC 的语言概括为具有一种共同的性能特征。例如,Oracle 的 HotSpot GC 文档把吞吐量与延迟区分为垃圾收集的主要性能指标,并说明不同收集器和配置在暂停时间、吞吐量与内存使用之间具有不同的权衡。因此,以“GC 会产生暂停,所以不适合系统软件”这样的方式进行概括过于宽泛。实际适用性取决于收集器与运行时、堆大小与存活对象、工作负载、延迟要求、内存约束和目标环境。24

在这一比较中,Rust 的技术差异并不是“没有 GC,所以自动更快”这一命题,而是通过所有权与借用规则静态检查相当一部分内存生命周期与别名关系,并在不需要单独运行时 GC 的情况下加强内存安全这一设计选择。在难以或不希望设置运行时收集器的环境中,或者底层控制与显式资源生命周期管理很重要的环境中,这一特性可以成为有力的采用理由。反过来,Safe Rust 也不会消除所有逻辑错误、一般竞争条件、内存泄漏或资源耗尽,而在涉及 unsafe 与 FFI 的边界仍然存在额外的健全性义务。22

中间结论

同时考虑内存安全与运行时成本的 Rust 设计,可以在特定系统软件中提供实质性的技术适配性。然而,这种适配性究竟在多大程度上促成了实际采用决策,是一个独立的经验问题。如果缺少组织决策记录、调查、迁移报告与比较资料,就不能仅凭技术优势的存在确定采用的唯一原因或平均效果。因此,本节整理的是 Rust 可能被采用的技术理由与适用条件;关于整体采用原因的结论,需要结合后续的工具、生态系统与叙事分析来判断。

2.2 开发者体验(DX):Cargo 与工具链

在解释 Rust 的采用时,以 Cargo 为核心的一致工具体验经常被视为一项优势。不过,这一主张包含两个不同层次。一个层次是功能事实,即 Cargo、rustup 等工具实际统一了哪些工作流程;另一个层次则是经验性和因果性主张,即这种统一在多大程度上促进了开发者生产力、上手过程以及组织的采用决策。前者可以通过官方文档确认,后者则需要单独的测量与比较。

Cargo 是 Rust 的官方包管理器兼构建工具,通过 manifest 与统一命令体系,把不同 Cargo 项目中的构建、检查、测试、文档生成等入口标准化。rustup 管理编译器及相关工具的 toolchain,默认安装 profile 中包含 rustfmt 与 Clippy。rust-analyzer 也是可安装的官方 component,项目还可以通过 rust-toolchain.toml 在仓库中指定 toolchain channel、component 与 target。25 这种共同的默认路径可能减少开发者在不同项目中重新学习命令和工具选择的成本。不过,官方功能文档本身并不测量上手时间或开发生产力改善了多少,因此不能把工具已经整合这一事实等同于开发者生产力更高这一结论。

实际使用资料也同时展示了这两个方面。Rust 项目的 2025 年编译器性能调查有 3,700 多名受访者,其中约 60% 表示在类型检查、构建和测试时使用 Cargo 的终端命令。这直接表明,在这些调查受访者的实际工作流程中,Cargo 占据中心位置。

不过,在同一调查中,选择其构建时间问题最严重的项目作答的受访者里,55% 表示小改动后的重新构建需要等待 10 秒以上;而在表示已经停止使用 Rust 的受访者中,约 45% 把较长的编译时间列为停止使用的原因之一。2025 State of Rust Survey 也继续把编译缓慢与存储空间使用列为限制生产力的问题,同时调查团队明确提醒,不应把约七千名受访者的结果过度推广到整个用户群体。26

因此,这些资料展示了以 Cargo 为中心的工作流程的实际使用及其成本,但并不能证明 Cargo 相比其他生态系统提高了平均生产力,也不能证明它是 Rust 被采用的原因。

同样,把 C 和 C++ 生态系统对比为“没有构建和包管理工具的环境”也不准确。CMake 提供配置、构建、安装、测试与打包工具以及 Presets;Meson 集成了构建、测试等常见开发任务。vcpkg 可以在 manifest 中直接声明依赖与版本约束,Conan 则可以跨多种构建系统和平台管理 C/C++ 依赖与二进制包。27 差异与其说在于工具是否存在,不如说在于默认路径的整合程度以及选择结构。Rust 生态系统中,Cargo 与 Rust 项目发布的多种工具形成了较强的共同惯例;而 C/C++ 环境则常常根据组织、平台与既有资产选择不同组合。前者可能有利于通过共同约定降低协调成本,后者则可以提供更大的选择空间,以适配既有构建系统、二进制分发方式和内部仓库策略。因此,不能断言其中任何一种结构在所有环境下都具有更低的总成本。

整合的默认工具链也不会消除组织层面的集成成本。rustup target add 会为交叉编译目标安装 Rust 标准库,但不会提供所有外部 linker 或 SDK;Rust 官方安装文档也说明,普通构建需要 linker,而某些 crate 因包含 C 代码可能还需要 C 编译器。28 对于已经拥有 monorepo、内部 build farm、private registry、安全与许可证检查、打包与部署体系的组织,可能需要把 Cargo 接入这些体系,或者与它们并行运行。在大规模、长期运行环境中,评估时除了共同命令的便利性,还应考虑 toolchain 固定与更新、CI cache 与构建时间、原生依赖、离线恢复、安全审计、迁移与 rollback 成本。依赖、vendoring 与供应链边界本身沿用前面第 1.5 节的分析。

中间结论

由 Cargo、rustuprustfmt、Clippy 与 rust-analyzer 构成的官方工具路径,是 Rust 明确的工程优势之一。共同的 manifest 与命令体系、toolchain 管理以及第一方工具的结合,可以让不同项目间的工作流程更可预测;调查资料也表明,Cargo 在许多受访者的实际开发流程中被广泛使用。不过,被广泛使用提高生产力导致采用是三个不同的命题。若要主张生产力或采用效果,还需要能够控制项目规模、团队经验、既有工具、构建环境与同步变化的比较资料,或者组织的决策记录。因此,本节能够确认的是整合工具体验这一技术特性及其适用条件,而不是 Cargo 是 Rust 被采用的普遍原因。

2.3 叙事建构与“议程设置”分析

本节所说的 叙事(narrative),是指为了让人理解某项技术试图解决什么问题以及为什么可能选择它,而以一定结构呈现问题界定、价值主张和比较标准的解释方式。这个术语并不预设存在一个中央主体统一控制信息,也不预设发生了有意操纵。议程设置(agenda-setting) 则采用更狭义的含义。McCombs 与 Shaw 1972 年的研究在特定的选举、地区、样本和时间范围内,比较媒体对不同议题的强调程度与选民认为哪些议题重要之间的关系。因此,某个主题只是在官方文档或在线讨论中反复出现,并不能据此确认开发者群体对重要性的判断已经发生变化这一议程设置效果。29

Rust 项目的官方资料可以直接确认它传达了哪些价值。2015 年 Rust 1.0 Alpha 公告把语言的重点描述为安全性、性能与并发;官方书籍则把利用所有权和类型检查在编译阶段处理许多并发错误的方法称为“fearless concurrency”。2018 年关于 rust-lang.org 改版的文章说明,团队重新审视了旧首页列举零成本抽象、内存安全、无数据竞争线程等特性的方式,并在新网站中把“Why Rust?”置于显著位置,同时修改了口号。在本书本次修订时,官方网站首页把 Performance、Reliability、Productivity 列为主要价值项目。30

这些资料能够直接证明的是:Rust 项目一直把安全性、性能、并发、生产力与工具体验作为官方价值主张,并且有意识地调整过这些价值的呈现方式。由此不能直接得出“整个 Rust 社区共享同一套叙事”“Rust 话语改变了系统编程的评价议程”,或“开发者和组织因为这些信息而采用 Rust”等结论。官方项目的信息、非官方社区话语、受众对什么重要的认知,以及实际采用决策,是不同的观察单位。

尤其是“由于 Rust 话语,内存安全成为系统编程的核心评价标准”这一命题,比“官方资料反复出现内存安全”这一观察更强。要对前者进行经验验证,需要定义所分析文档与帖子的总体或样本、纳入与排除标准、时间范围、比较对象、衡量各主题强调程度的方法,以及能够反映受众认为哪些标准重要的资料。没有这样的研究设计时,本节能够确认的范围,是 Rust 官方沟通持续把内存安全及相关价值置于突出位置,以及这种沟通可能为注意力和解释提供了框架。社区整体的议程设置效果及其大小仍未得到确认。29

非官方在线话语也应采用同样的证据标准。部分帖子或重复表达可以作为某种论证结构确实存在的质性案例,但要得出这种表达常见或占主导地位的结论,就需要定义总体、抽样方法与时间范围。同样,“学习 Rust 有助于理解某些问题”这一教育性主张,与“因为是 Rust 用户,所以更聪明或更有资格”这一对人的地位判断,在逻辑层次上并不相同。后者实际存在的频率及其作用,不应从少数选取案例推广;第 8.5 节与第 9.2 节将结合独立的话语资料进行分析。

叙事对实际采用的影响同样是独立的因果问题。官方信息可能使某些优势更加醒目,并提供比较标准,但要判断它在多大程度上改变了开发者的学习与偏好,或组织的采用决策,需要能够把接触、认知与决策连接起来的直接证据,例如调查、实验、纵向资料或组织决策记录。机构与企业支持对信任或采用的影响不与这个问题混在一起,而在下一节 2.4 中另行讨论。

中间结论

文档可以确认,Rust 项目正式把安全性、性能、并发、生产力与工具体验作为重要价值提出,并通过网站和文档调整过这些价值的传达方式。但是,官方价值主张的存在、非官方话语中的重复、受众对重要性的认知变化,以及对实际采用的因果效果,是彼此不同的命题。因此,本节确认 Rust 官方沟通与叙事建构的存在,但在没有定义明确的话语样本与受众资料时,不确认社区整体的议程设置或采用效果。

2.4 机构支持与社区文化

必须区分机构和企业支持 Rust 这一事实,与“这种支持提高了信任、正当性或采用”的效果主张。Rust Core Team 在 2020 年说明,Rust 最初是 Mozilla Research 的项目;2015 年 Rust 1.0 之后,项目方向与治理从 Mozilla 组织中独立出来,但 Mozilla 仍继续担任主要的资金与法律支持者。2021 年 Rust Foundation 成立时,AWS、Huawei、Google、Microsoft、Mozilla 作为创始成员参与,基金会董事会由这些成员公司一方的 5 名董事和 Rust 项目一方的 5 名董事组成。31

在这段历史中,也不能把 Rust Foundation 的制度性支持Rust 项目的技术决策视为同一件事。讨论成立基金会时,Rust Core Team 说明,基金会将为法律、资金和维护者支持提供基础,而大多数 Rust 团队的工作范围与决策权限不会改变。在本书修订时,Rust 项目的官方治理仍另外设有 Leadership Council 和多个 top-level team。因此,基金会成员公司的参与并不意味着这些公司直接控制语言或编译器的技术决策。反过来,法律主体、资金支持、基础设施与维护者支持体系的存在说明了项目的运行条件,但这些条件在多大程度上改变了外部组织的信任或采用决策,是另一个经验问题。31

基金会的成立公告把创始企业的长期资金承诺解释为一个信号,即 Rust 已经在企业环境中成为 production-ready 技术。不过,这是基金会自身的官方解释,并不是对外部组织认知或采用效果的独立测量。若要主张企业支持影响了信任、正当性或采用,还需要额外的调查或比较资料,说明在决策记录中支持是否确实是评价因素、支持前后的认知如何变化,以及其他技术和组织因素如何得到控制。31

对于社区文化,也必须区分 官方规范与资源的存在整个社区的实际行为与结果。Rust 的行为准则以在官方 Rust 空间中提供友善、安全且欢迎参与者的环境为目标,并规定对违规行为的 moderation 与处置程序。Rust 官方学习页面把 The Rust Programming Language 作为入门资料,Book 本身也组织了包括安装、Cargo 使用、所有权等内容的语言学习路径。32 这些资料说明 Rust 项目正式提供了哪些规范与学习资源,但并不能证明所有互动都符合这些规范,也不能证明非官方 Rust 社区整体都呈现相同文化。

同样,仅仅存在行为准则和学习资料,并不能证明进入门槛确实降低、学习时间缩短,或新参与者的留存率和多样性提高。评估这些效果需要调查或比较研究,把新用户和贡献者的体验与流失、留存资料,学习时间与成功率,以及文档使用情况连接起来。从大规模、长期运行的角度,与其只看支持机构的数量,更应同时评估法律与财务责任的持续性、对特定支持者的依赖程度、治理与技术决策的分离,以及基础设施或维护者支持中断或变化时的应对能力。Rust 项目在 2020 年基金会筹建过程中明确提出通过多样化基础设施支持来降低对单一支持者的依赖,也与这一点有关。31

中间结论

Mozilla 的长期支持、独立 Rust Foundation 的成立、企业与项目代表共同参与的基金会结构、Rust 项目的行为准则与官方学习资源,都是可以从文档确认的制度与社区基础。但是,支持体系的存在官方规范与资源的存在信任、学习或社区行为的变化以及 对实际采用的因果效果是不同的命题。因此,本节确认 Rust 拥有制度性支持与官方社区实践,但在没有直接结果资料的情况下,不确认它们是采用或社区结果的普遍原因。

2.5 采用因素综合与第2章结论

前几节确认的是,在解释 Rust 的采用时可以考察的若干不同因素。第 2.1 节确认了在同时需要内存安全与低层控制的部分环境中的技术适配性;第 2.2 节确认了 Cargo 与官方工具链提供的共同工作流程;第 2.3 节确认了 Rust 项目正式提出的价值与叙事建构;第 2.4 节确认了 Mozilla 的支持、Rust Foundation 的制度基础、行为准则与学习资源。然而,仅仅因为这些因素同时存在,并不能据此断定它们构成了一条导致 Rust 被采用的因果链,或彼此放大了效果。

这一划分会随着本章所说的 采用范围 而更加重要。试验性使用、引入新组件、部分替换现有系统、团队级使用和组织标准化是不同的决策,同一种技术特性或工具在不同范围中的权重也可能不同。因此,某个案例使用了 Rust,只能说明在那些条件下采用是可行的且 Rust 被选择了,并不能说明哪个因素具有决定性,也不能说明其效果会在其他范围或组织中重现。

第 2.1~2.4 节的证据边界也必须保持不变。技术适配性能够解释可能的选择理由,但并未测量其对实际决策的贡献程度;以 Cargo 为中心的工作流程被广泛使用到什么程度,与它对生产力或采用产生什么效果,也是不同的命题。官方价值主张、制度性支持、行为准则和学习资源的存在同样可以从文档中确认,但受众认知的变化、整个社区的行为、外部组织的信任以及对实际采用的影响,都需要单独的结果资料。本章现有资料也不足以对这些因素的相对重要性进行排序。

认为这些因素彼此 发生了相互作用 是一种可能的假设,但它本身不是观测结果。若要进行经验性主张,需要调查、决策记录、纵向数据或其他相当的研究设计,把技术评估、工具体验、信息接触、制度条件与实际决策连接起来。同时还必须考察其他解释,包括现有代码与接口、团队经验与人员构成、架构与运行约束、安全与采购政策、进度与成本,以及同时发生的重新设计或流程变化。如果不控制这些条件,仅凭成功案例或采用案例,很难分离语言、工具、支持或叙事各自的独立效果。

第2章结论

文档和资料能够确认的是:Rust 具有可能适合部分系统软件环境的技术特性、集成的官方工具路径、反复提出的官方价值主张,以及制度性支持与官方社区实践。这些因素为特定组织或开发者评估并选择 Rust 时提供了可以考虑的理由与条件。但是,潜在采用理由的存在它们在实际决策中的贡献程度多个因素之间的相互作用以及 可以推广到其他组织的平均因果效应,是彼此不同的命题。

因此,本章不以单一的技术优越性或单一的叙事效果来解释 Rust 的采用。当前确认的资料足以识别多个候选因素与适用条件,但不足以一般性地确定哪个因素在何种采用范围内具有多大决定性。后续的产业案例和比较分析同样不应把采用本身当作技术优越性的证据,而应分别考察各案例的决策记录、系统条件、同时发生的变化与替代选择。第二部分将把这一因果问题与技术分析区分开来,分析安全性、所有权等 Rust 主要设计原则本身提供的保证、成本及其历史关系。


第二部分:主要设计原则的技术分析

第一部分考察了 Rust 的技术特性与相关叙事。第二部分将从技术上分析 Rust 的主要设计原则——安全性与所有权。

本部分从多个角度检视这些原则被评价为“创新”的依据、工程权衡,以及这些概念如何关联到 C++、Ada 等编程语言历史中的先例。同时,把现有代码库的重构、现代化、部分替换和全面重写区分为不同的变更策略,并建立分析标准,避免把语言层面的保证与项目层面的改善效果等同起来。

3. 对“安全性”叙事的多维分析

本章所讨论的“安全性(safety)”并不是单一且不可分的属性。Rust 的语言保证、编译器与库的实现、运行中的失败模式、改变现有系统的策略,以及技术话语中“安全性”一词的使用,属于不同的分析单元。因此,本章不预设“Rust 是安全的”或“现有语言不安全”这类笼统命题,而是分别考察哪些属性在什么条件下得到保证。

第 3.1 节首先考察 Rust 设计与先行语言、技术之间的历史关系,同时区分 历史先例概念相似性官方资料所确认的直接影响。第 3.2 节分析 Safe Rust 的技术保证,以及 unsafepanic、内存泄漏、逻辑错误等边界。第 3.3 节把 C/C++ 的渐进改进、部分替换和使用 Rust 重写作为不同的变更策略加以比较。第 3.4~3.5 节在共同的比较标准下考察 Ada/SPARK 与基于 GC 的语言,第 3.6 节则与技术事实分开,讨论“安全性”在话语中如何被使用。最后,第 3.7 节把这些结果综合为设计上的工程权衡。

这样的顺序旨在避免把历史先例等同于当前保证、把强语言保证等同于项目转换成功的保证,或把某种话语表达的存在当作技术优越性的证据。

3.1 “创新”的含义与历史先例分析

技术上的“创新”并不一定意味着“此前不存在任何相关概念”。新的组合、适用范围、规则的强制位置、易用性或实现方式本身都可能构成创新。反过来,两种技术相似这一事实,也不足以证明其中一种直接源自另一种。本节仅在 Rust 项目的一手资料明确指出某项影响时使用 直接影响 一词,其余关系则限定为历史先例或概念相似性。

C++ RAII 与 Rust 所有权:有文档记录的影响与不同的强制位置

Rust Reference 明确把 C++ 的 references、RAII、smart pointers、move semantics 列为 Rust 设计的影响来源。Rust 官方 Book 也说明,值的生命周期结束时通过 drop 释放资源的模式,在 C++ 中称为 RAII。C++ Core Guidelines 建议把资源封装到对象中,以构造函数和析构函数的生命周期规则配对资源获取与释放,并把负有资源释放责任的对象视为 owner。33 因此,C++ RAII 及相关资源管理技术对 Rust 产生影响,并不只是外观上的相似,而是由官方资料确认的历史联系。

不过,这并不意味着“资源所有权这一一般概念首先由 C++ 发明,Rust 只是将其直接扩展”。Rust 在确定性资源释放之外,还结合了其他规则:所有权移动后限制原 binding 的继续使用,并通过借用规则静态限制可变访问与共享访问之间的 aliasing 关系。同一份 Rust Reference 还把 ML Kit 与 Cyclone 的 region-based memory management 分别列为 Rust 的影响来源。33 因此,把 Rust 的内存与生命周期设计还原为单一的 C++ 谱系同样不准确。本节只确认这种关系的存在以及规则强制位置的差异;Safe Rust 究竟保证什么留到第 3.2 节分析,RAII 与 Rust 所有权的详细比较则留到第 4.1 节。

Ada 与 SPARK:更早的高可靠性与验证谱系,但并非相同的所有权谱系

Ada 1983 标准早于 Rust,Ada Reference Manual 把程序的可靠性与可维护性、人的编程活动以及效率列为原始设计的主要关注点。Ada 的类型与 subtype 体系以及由语言定义的运行时检查,形成了把部分错误转化为明确检查失败的传统。最初的 SPARK 语言同样以 Ada 83 为基础,并发展出一条独立的高保证谱系:利用静态分析与 verification condition 验证初始化、信息流、不存在运行时错误以及明确的 contract 等属性。34 从这一意义上说,当检视“在 Rust 之前不存在同时处理安全性与效率的系统语言或验证技术”这类主张时,Ada/SPARK 是重要的历史比较对象。

然而,如果把这直接变成“Ada/SPARK 已经实现了与 Rust 相同的无 GC 内存安全模型”或“Rust 直接受到 Ada/SPARK 影响”的主张,就超出了证据范围。本节所核对的 Rust Reference 影响列表明确列出 C++、SML/OCaml、ML Kit、Cyclone 等,却没有把 Ada 或 SPARK 列为直接影响。并且,当前 SPARK 的 pointer ownership policy 是后来增加的功能,AdaCore 说明其 pointer support 基于 Rust ownership model。34 因此,本节把 Ada/SPARK 作为 高可靠性目标以及静态、形式化验证的历史先例进行比较,而不把它视为 Rust ownership 的直接祖先。SPARK 的 proof 也是针对明确属性、假设与分析范围的证明,而 Rust borrow checker 的自动检查具有不同的保证单元;如果不先定义比较属性,就没有意义笼统地把其中一方排为“更广”或“更强”。

代数数据类型与错误表示:缩小直接影响主张的范围

Rust Reference 明确把 SML 与 OCaml 的 algebraic data types、pattern matching、type inference 列为 Rust 设计的影响来源。Rust 的 Option<T> 包含 NoneSome(T)Result<T, E> 包含 Ok(T)Err(E);OCaml 的标准 option 也使用 NoneSome 在类型中表示值的缺失与存在。35 因此,Rust 以类似 sum type 的数据类型表示值缺失或成功、失败的方式,可以放在函数式语言传统中加以说明。

不过,官方影响列表直接支持的范围只是 SML/OCaml 的 ADT、pattern matching 与 type inference 对 Rust 的影响。仅凭这些资料,不能断言 ResultOption 的具体 API 直接源自 Haskell 或 OCaml 的某个特定错误处理 API,也不能说 Rust 原样借用了“单子式错误处理”。穷尽式 match 可以静态检查 variant 的覆盖情况,但 Rust 也不会强制所有错误处理代码始终显式写出每一种情况。这里能够确认的是基于类型表示状态这一设计谱系及其在 Rust 中的具体表达,而不是所有错误处理机制都来自同一条谱系。35

中间结论

把历史上可以直接确认的关系与比较对象分开后,图景会更清楚。C++ 的 RAII、smart pointers、move semantics,以及 SML/OCaml 的 ADT 等,是 Rust Reference 记录为直接影响的因素。Ada 与早期 SPARK 是 Rust 之前高可靠性工程与形式化验证谱系中的历史比较对象,但本节资料不足以断言它们直接影响了 Rust;相反,当前 SPARK 的 pointer ownership 是后来参照 Rust 模型加入的。因此,与其把 Rust 的原创性理解为“此前完全没有先例”,更准确的考察方式是分析它如何把多种先行思想结合到特定的所有权、借用规则以及语言与工具体系中,并对这些规则实施强制。这样的组合究竟提供什么保证、带来什么成本,是与历史先后关系不同的工程问题,后续各节将按属性分别分析。

3.2 Rust“安全性”的定义、边界与局限

本节的问题不是“Rust 是否安全”,而是 Safe Rust 在什么条件下保证什么,以及这种保证在哪里终止。语言层面的安全契约、unsafe 实现的 soundness、编译器、库和操作系统等实现与外部系统的正确性,以及服务可用性,是彼此不同的分析单元。把它们统称为一种“安全性”,既会夸大 Rust 的实际优势,也会夸大它的实际局限。

因此,3.2.1 节整理 Safe Rust 与未定义行为(Undefined Behavior, UB)的关系;3.2.2 节不把 unsafe 和 FFI 视为“放弃保证”,而把它们分析为由明确 safety contract 和 proof obligation 界定的边界;3.2.3 节区分 panic 的 unwind 与 abort 策略以及隔离、恢复的局限;3.2.4 节说明内存与其他资源泄漏为何不属于 memory safety 保证;3.2.5 节则考察逻辑错误、一般 race condition、死锁、资源耗尽、安全漏洞与 memory safety 之间的区别。

3.2.1 “安全性”的定义:防止未定义行为

Rust Reference 把 UB 定义为程序不得执行的一组行为。当前列表包括 data race、基于 dangling 或错误对齐 pointer 的无效内存访问、违反 aliasing 规则、以错误 ABI 调用函数、构造 invalid value 等。Reference 并不声称这份列表本身构成完整的形式语义,并明确指出这一边界今后仍可能调整。36

更准确地说,Safe Rust 的核心契约是:当 safe caller 使用 sound 的 safe interface 时,保证其不能通过这些 interface 引发 UB。这不同于一种经验性预言,即“只要源代码里没有 unsafe,整个程序无论出于什么原因都绝不可能发生 UB”。Safe Rust 代码可以调用标准库或第三方库的 safe API,而这些 API 的内部实现可能包含 unsafe。如果内部实现没有履行 safety contract,使 safe caller 能够引发 UB,那么按照 Rust Reference 的术语,该实现就是 unsound36

具体错误类型也必须按同一标准区分。解引用已经不再存活的 allocation,或创建并使用无效 reference,都可能构成 UB;Rust reference 必须正确对齐、non-null 且不能 dangling。data race 同样属于 UB。相比之下,安全的数组或 slice 普通索引如果在运行时超出范围,会执行边界检查并进入 panic,不能因此直接称为由 buffer overflow 引起的 UB。get_unchecked 等省略边界检查的操作属于具有额外 safety condition 的 unsafe 操作;违反这一条件才进入 UB 的边界。37

这一划分对于区分语言保证与实现正确性非常重要。Rust 语言模型对 safe interface 要求的契约、某个具体 rustc 版本是否正确实现了该语义、标准库或 crate 内部的 unsafe 是否 sound,以及操作系统、硬件、foreign code 是否履行各自的契约,都是不同的问题。编译器缺陷或 unsound 的库实现确实可能在实际运行中破坏内存安全,因此属于重要的实现风险;但不能把这一事实改写成另一项不同的主张——“Safe Rust 的语言规则允许 UB”。

3.2.2 unsafe 关键字与 FFI、外部契约的边界 {#322-unsafe-关键字与对-c-abi-的依赖}

unsafe 并不是关闭所有权、类型、lifetime 等 Rust 规则的开关。Rust Reference 把 unsafe 描述为一种标记:它为编译器不会检查的额外 safety condition 建立 proof obligation,或声明其他位置建立的该义务已经得到满足unsafe fn 可以定义 caller 必须满足的额外条件,而 unsafe { ... } 则表示程序员声称已经满足块内 unsafe operation 的条件。即使进入 unsafe,UB 仍然是不合法的程序行为,其他类型检查和语言规则也不会消失。38

因此,责任并不会固定转移到某一方。unsafe fn 文档化的前置条件需要 caller 满足;但把 unsafe 隐藏在内部的 safe abstraction 恰恰相反,要求实现者确保对所有 safe input 都维持内部 safety condition。一个 safe API 要想 sound,就必须让 safe caller 即使不知道任何未文档化的 safety condition 也不能引发 UB。因此,“一旦使用 unsafe,所有安全责任就转移给 caller”并不是准确的描述。必须按具体 API 判断由谁定义哪项 contract,以及由谁在什么边界履行 proof obligation。38

FFI 是这一边界清晰显现的代表性例子。external block 是声明当前 crate 之外定义的 item 的 FFI 基础;Rust Reference 把它视为类似 unchecked import 的边界。在 Rust 2024 Edition 中,external block 本身必须标记为 unsafe extern,声明的编写者负责保证函数与 static 的 signature 和实际外部定义一致。除非外部 item 被明确声明为 safe,调用或访问它通常需要 unsafe。39

但不能把 FFI 等同于 对 C ABI 的普遍结构性依赖"C" ABI 是非常重要的互操作路径,也是 external block 省略 ABI 字符串时的默认值,但 Rust 还定义了 "system""C-unwind" 等其他 ABI;低层功能也可能通过 FFI 之外的 unsafe operation 或平台专用接口实现。一个实际系统在多大程度上使用 C ABI,是其目标操作系统、库、硬件与集成架构的属性。Rust 的语言层边界并不是“使用了 C”,而是 由谁、依据什么来保证编译器无法验证的外部契约39

在大规模系统中,这一区别直接关系到可维护性与故障隔离。FFI wrapper 可以在狭窄的内部边界验证 pointer 有效性、长度、ownership、lifetime、aliasing、ABI、error 和 unwind 约定,并只向外暴露 sound 的 safe API,从而把风险局部化。反过来,如果 safe API 内部的 unsafe、外部库或 ABI 声明有误,即使调用端完全用 Safe Rust 编写,整个程序也可能受到影响。因此,Safe Rust 的优势不是消灭所有未经验证的义务,而是能够把许多义务从 safe caller 隔离出来,集中到较窄的边界上。

3.2.3 “安全失败”与 panic 的含义

panic 定义成一种普遍适用的“安全失败(safe failure)”模型并不准确。像安全数组索引的边界检查那样,已定义的 safe operation 在发现错误条件后执行 panic 本身并不是 UB;但程序和服务之后如何运行,取决于 panic strategy 与隔离结构。

Cargo 和 rustc 大体上把 panic strategy 区分为 unwindabort。在 unwind 中,panic 会展开 stack,并可以在该路径上执行清理;在 abort 中,process 会终止。实际采用的策略可能因目标平台和构建配置而不同,因此不能笼统地说“panic 默认总会展开 stack,并且只终止当前 thread”。更广泛地说,Rust 的安全契约本身也不保证所有 destructor 必然执行。40

std::panic::catch_unwind 也不是通用的异常处理或服务恢复保证。它只能捕获 unwinding panic,不能捕获 aborting panic。标准库文档指出,对于正常运行中可能发生的失败,Result 更合适,并不建议把 catch_unwind 当成一般 try/catch 机制。其 closure 还受 UnwindSafe 边界约束;panic 过程中部分修改的状态或已经破坏的逻辑 invariant 是否会被后续代码观察到,也必须单独处理。40

thread 边界同样不等于“自动恢复”。在 unwind 策略下,子 thread 发生 panic 时,JoinHandle::join 可以把它作为 Err 观察,因此可以把 thread 设计成一个隔离单元。但要把这种观察真正转化为服务恢复,caller 仍需处理 Err、确认共享状态的一致性,并为失败工作定义重试、丢弃或 restart 策略。若使用 panic = "abort",process 本身可能终止;再次 unwrap join 结果或把 panic 传播到更高边界的设计也可能使服务中断。40

因此,memory safety 与 availability 是不同的属性。panic 是已定义的控制流而不是 UB,这一事实本身并不保证请求隔离、thread/process 边界、supervisor 与 restart、状态恢复、retry 策略或受限的故障传播范围。对于长期运行的服务器、嵌入式或 mission-critical 系统,必须分别设计 panic strategy、失败能够传播到哪一个 execution boundary,以及之后如何恢复服务。

3.2.4 “安全的”内存泄漏问题

Rust Reference 明确把内存和其他资源的 leak 列为不被视作 unsafe 的行为。这里的“safe”并不意味着在运行上理想或不会发生故障,而只是说 leak 本身不是违反 Rust memory-safety contract 的 UB。41

这一边界在标准库的 std::mem::forget 中尤其清楚。mem::forget 是一个 safe 函数,它取得值的 ownership 后,可以在不运行 destructor 的情况下忘掉该值。文档解释说,Rust 的 safety guarantee 并不包括 destructor 必须执行,因此该函数无需是 unsafe;文档还把 Rc<T> 引用环和 process 终止列为 destructor 可能不运行的其他情况。Rust Book 同样说明,使用 Rc<T>RefCell<T> 构成 reference cycle 可以在 Safe Rust 中造成内存 leak。41

这不仅是术语问题。泄漏的 heap memory、file descriptor、socket、lock 等有限资源,在长期运行的 process 中可能造成资源耗尽、latency 上升、请求失败,并最终导致服务中断。因此,memory-safe 的 leak 并不等于 availability-safe 的行为。在大规模、长期运行环境中,不仅是内存,descriptor、connection、task、queue 等有限资源也需要用单独的 invariant 管理其上限和回收路径。

此外,unsafe 实现不能让 soundness 依赖“caller 最终一定会执行 Drop”这一假设。safe caller 可以使用 mem::forget,process 也可能在不运行 destructor 的情况下结束。这个原则表明,Rust 的安全边界比简单的 RAII 说明更宽,resource lifecycle 与 memory-safety proof obligation 应当分开处理。

3.2.5 保证范围之外的问题:逻辑错误、死锁等

Safe Rust 的强保证不会自动扩展到所有 correctness、security 与 availability 属性。Rust Reference 不把 deadlock 和 memory/resource leak 视为 unsafe;safe code 即使违反额外的逻辑条件,结果可能表现为 panic、错误计算结果、abort 或 non-termination,但这并不因此等同于 UB。42

尤其需要区分 data race 与一般 race condition。data race 在 Rust 中属于 UB,也是 Safe Rust 重点阻止的类型。但 borrow checker 不会消除所有由执行顺序决定结果的一般 race condition,也不会自动消除 TOCTOU、错误的 protocol state transition、livelock 或 starvation。Rustonomicon 同样区分:Safe Rust 保证不存在 data race,但并不防止一般 race condition。43

整数 overflow 也必须按同样方式精细划界。Rust Reference 把 arithmetic overflow 视为程序员错误,但并不直接把它归类为 UB。在启用 debug_assert! 的配置中,实现必须插入动态检查并在 overflow 时 panic;在其他 build 中,实现可以选择 panic 或隐式 wrapping。发生隐式 wrapping 时,结果按 two’s-complement 规则定义。Cargo profile 通过 overflow-checks 控制运行时 overflow 检查,因此把行为简单固定为“debug 会 panic,release 总是 wrapping”并不准确。42

安全漏洞的范围同样比 memory safety 更广。Rust Security Response WG 在 2024 年公开的 CVE-2024-24576 涉及 Windows 上 std::process::Command 执行 batch file 时参数 escaping 不充分;在攻击者能够控制不受信任 argument 的条件下,该缺陷可能导致执行任意 shell command。这个 API 可以通过 safe 调用,但核心原因并不是 memory corruption,而是命令参数处理与 API contract 中的逻辑缺陷。原问题在 Rust 1.77.2 中修复;之后又报告了单独的不完整修复问题 CVE-2024-43402,其中 trailing whitespace 和 period 可以绕过缓解措施,并在 Rust 1.81.0 中得到补充修复。44

从这些案例能够得出的结论是有限的。某些过去版本的标准库曾存在逻辑型安全缺陷,并不能说明整个 Rust 生态系统的漏洞频率,也不能说明当前版本的风险。反过来,Safe Rust 的 memory-safety contract 很强,也不能作为 command injection、认证或授权错误、protocol bug、resource exhaustion、deadlock、错误状态转移、服务恢复失败会自动消失的证据。

中间结论

Safe Rust 的重要工程优势,是在 sound 的 abstraction 边界内强制 safe caller 不能引发特定类别的 UB 与 data race。但这一保证并不会把 compiler correctness、unsafe implementation 的 soundness、FFI 与外部系统的 contract、一般 race condition、逻辑正确性、资源上限、panic 隔离与服务恢复合并成一种保证。“memory safety”“security”“correctness”“availability”“resilience”可能彼此相关,但不应被当作同一属性评价。这一区分将作为下一节比较其他语言与变更策略的标准;它本身并不能证明某种语言迁移策略具有优越性。

3.3 比较分析 1:C/C++ 的多层安全保障与变更策略

本节的问题不是“是否应该把 C/C++ 换成 Rust”,而是:在考虑既有系统的缺陷模型与资产、过渡风险和保证要求后,应选择或组合哪些变更策略。第 3.2 节确认的 Safe Rust 保证是语言选择的重要输入,但仅凭这些保证,无法决定维护、现代化、选择性替换、新开发或全面重写中哪一种策略最优。

比较变更策略时,至少必须区分两类效果。一类是变更后的实现能够预防、检测或缓解哪些缺陷;另一类是变更本身带来的规范恢复、兼容性、部署、回滚、双重运行、人员与长期维护成本。前者属于目标状态的质量问题,后者属于过渡过程的风险。只计算其中一侧,会高估语言保证或既有资产的价值。

3.3.1 区分重构、现代化与重写

本书把变更策略区分如下。这里的分类是为了明确本节的比较单位而采用的工作定义,并非适用于所有方法论的普遍分类体系。

  • 维护与缺陷加固: 不替换既有实现和外部行为,而是加强缺陷修复、输入验证、隔离、加固、测试与可观测性。
  • 重构: 在保持外部可观察行为的同时改善内部结构。Martin Fowler 同样把重构定义为不改变可观察行为而改变内部结构。45
  • 现代化: 更广泛地改善新的语言特性和库、构建与分析工具、API、模块边界、部署结构等。必要时也可以有意改变外部行为或运行方式。
  • 选择性替换: 只把风险较高或变更价值较大的部分组件换成新实现,同时与系统其余部分共存。可以更换语言,也可以用同一种语言重新实现。
  • 引入新组件: 不替换既有实现,而用另一种语言编写新功能或新服务。
  • 全面重写: 用新实现替换既有实现的广泛部分。由于语言迁移也可以是局部的,“语言迁移”和“全面重写”同样不是同义词。

因此,“用 Rust 重写 C/C++”并不是重构的同义词。 它可能属于选择性替换、全面重写,或更广泛语言迁移的一种形式。反过来,引入 Rust 也不一定意味着重写:可以只用 Rust 编写新组件,或只替换狭窄的高风险模块而保留周围 C/C++ 系统。

3.3.2 C/C++ 内部重构与现代化的实际价值

C 与 C++ 的改进手段不能归约成一个与 Safe Rust 等同的语言保证。设计规则、类型与资源管理惯用法、静态分析、运行时插桩、测试与模糊测试、隔离和 exploit mitigation 工作在不同层次。因此,必须区分预防(prevention)、检测(detection)与缓解(mitigation)

C++ Core Guidelines 建议通过 RAII 与 resource handle 自动管理资源,用 unique_ptrshared_ptr 表达 ownership,并用 span 等表示范围。同时,Guidelines 的设计允许在既有代码库中渐进采用,并非所有规则都由语言本身强制。clang-tidy 也提供 cppcoreguidelines-*clang-analyzer-*bugprone-* 等可选检查,但其范围受限于已启用分析能够诊断的模式。46

动态工具的性质更加明确。Clang 的 AddressSanitizer 会在经过插桩的执行中检测 heap、stack、global 的越界访问、use-after-free、invalid free 等多类内存错误,ThreadSanitizer 检测 data race,UndefinedBehaviorSanitizer 则在运行时插桩所选 UB 检查。这些工具对发现 C/C++ 缺陷很有价值,但并不是覆盖未执行路径的语言级不存在证明。

它们也有成本:当前 Clang 文档把 AddressSanitizer 的典型运行时开销描述为约 2 倍,把 ThreadSanitizer 描述为约 5~15 倍运行时间以及约 5~10 倍内存开销。ASan 与 TSan runtime 也并非为链接进 production executable 而设计,文档警告,在安全敏感环境中用于 production 本身可能带来风险。

因此,在大规模、高负载、实时环境中,需要按工具区分部署边界:ASan、TSan 这类检测 runtime 主要放在 CI 与测试中,而 canary 或 production 应选择已单独确认适合该环境的 instrumentation 或 mitigation。46

C 代码同样可以通过 allocator/free 契约、携带长度的 buffer interface、单一 ownership 规则、狭窄 foreign interface、静态与动态分析以及 fuzzing 来降低风险。但如果这些规则依赖组织 convention、API discipline 或特定 toolchain 配置,其保证位置和强度就不同于 sound Safe Rust interface 提供的语言级契约。

层次 代表手段 主要效果 保证或运行层面的局限
设计、类型与资源管理 RAII、smart pointer、span、明确的 ownership/length 契约 缩小危险 lifetime 与 buffer 操作范围 raw pointer、legacy API、FFI 与绕过规则的路径仍需单独管理
静态分析 clang-tidy、Clang Static Analyzer 等 提前诊断启用分析能够推断出的源码缺陷与规则违反 依赖启用的检查和分析精度,并非全语言的不存在保证
动态分析 ASan、TSan、UBSan 在插桩执行中检测特定 memory/UB/data-race 缺陷 依赖执行路径和环境,并产生时间与内存成本
测试与模糊测试 回归测试、property-based test、coverage-guided fuzzing 通过执行验证既有行为和边界条件 test oracle 或 coverage 不完整时可能漏检
隔离与加固 sandbox、memory tagging、hardened allocator、exploit mitigation 降低缺陷的可达性、影响或可利用性 不会消除所有缺陷,并可能增加性能、内存或运行成本

这一多层方法不提供与 Safe Rust 相同的保证,这一点很重要。但保证更弱或位于不同层次,与工程效果为零是两个不同命题。 反过来,大量使用 sanitizer 和 guideline 也不能证明 C/C++ 代码获得了与 Safe Rust 相同的 memory-safety contract。

Android 当前文档也把这种区分用于实际运行策略。AOSP 说明多数新 native project 倾向使用 Rust,同时明确指出,把所有既有 memory-unsafe code 全部用 Rust 重写并不现实,Rust 是对 memory-safety tooling 的补充。既有 C/C++ 继续使用 HWASAN、KASAN、GWP-ASan、memory tagging 等检测与加固。47 这个案例表明,改进 C/C++ 与采用 Rust 并非对立关系,在大规模过渡期可以同时进行。但这并不意味着 Android 的代码结构和漏洞分布可以直接推广到其他项目。

3.3.3 Rust 重写新增的保证与新产生的风险

对于新用 Rust 编写或替换的范围,可以在第 3.2 节的条件下把 Safe Rust 的 memory-safety contract 作为设计默认值。这是区别于 guideline 或 sanitizer 检测的重要优势。尤其当 memory-safety 缺陷影响重大、unsafe 与 FFI 边界能够保持狭窄,并且组织有能力在预期生命周期内维护组件时,语言级预防的价值更高。

但是,目标语言状态的保证与“重写”这种变更方式是不同的分析单位。 重写要求新实现重新满足既有系统所需的行为、兼容性、性能特性和运行契约。正如 Martin Fowler 在讨论渐进替换时所指出的,既有系统的实际行为可能包含比替换开始时想象的更详细规范,而一次大规模 cut-over 会把风险集中在一个事件中。Strangler Fig 是基于这些问题提出的渐进 replacement pattern,而不是证明所有系统中部分替换总比全面重写更优的经验定律。48

更换语言会产生以下独立验证问题。

  1. 行为规范与 test oracle: 必须决定哪些 legacy behavior 必须保留,哪些 behavior 有意移除。如果既有测试不足,新实现“等价”的含义本身可能不明确。
  2. interop 与 safety boundary: 与既有 C/C++、操作系统接口、driver、library 共存时,需要重新明确 FFI、ABI、ownership、error、unwind 契约。第 3.2 节的边界仍然有效:unsound 的边界会影响完全以 Safe Rust 编写的调用方。
  3. 部署、rollback 与状态兼容性: 并行或分阶段过渡需要明确设计 protocol、data format、persistent state 与 rollback 兼容性。
  4. 性能与运行成熟度重新验证: 新实现必须在目标 workload 下重新验证,不仅是平均性能,还包括 tail latency、peak memory、startup、failure mode、rare input、observability 与 recovery behavior。
  5. 长期组织成本: 必须评估组织能否在过渡期间或更长期的共存期维护两种语言和 toolchain,以及 dependency、build、debugging、code review、招聘与培训。

Android 是把这一问题作为以 interop 为中心的渐进过渡来处理的代表案例。Android 团队认为全面重写既有 C++ 并不现实,把既有代码与 Rust 的互操作分析为实际前提条件。2024 年的 firmware 案例优先处理新代码和安全风险高的既有代码,并说明通过保留既有 C API 的 thin Rust shim 进行选择性替换的路径。49 这表明部分采用在大型系统中可以成为实际策略。不过,2021 年 interop 分析是用 Android platform 中实际使用的 exported C++ API 与 type 评估兼容性和实用性,并不是测量任意代码库接口成本或适用性的普遍证据。

这些案例也不能推出相反的普遍命题,即“full rewrite 总是错误”。Android 团队用 Rust 重写了 Android Virtualization Framework 的 protected-VM firmware,使其成为 pVM root of trust 的 memory-safe foundation。50 当保证收益高的边界狭窄、要求与验证范围可控,而且没有充分理由保留既有结构本身时,组件级重写可能是合理选择。

因此,更换语言不是简单消除风险,而是改变风险的种类与位置。把有限范围迁移到 sound Safe Rust 可以降低特定 memory-safety 风险,但过渡范围越大,就越需要同时控制规范恢复、interop、部署、rollback、运行成熟度与组织能力相关的风险。净效果不应按代码行数判断,而应把这两类风险放在同一基准上比较。

3.3.4 变更策略的连续谱与选择性采用

真实项目不必把下面的策略视为互斥选项。同一系统可以保留并加固成熟 C++ 模块,用 Rust 编写新 native component,只选择性替换处理 untrusted input 的高风险 parser,并重写结构上已到寿命末期的小型 subsystem。

变更策略 优先确认的条件 可以获得的主要效果 主要过渡与运行风险
保留现有实现并加固缺陷 缺陷局部集中,且变更风险更高 最小过渡范围,保留既有行为资产 结构债务与 memory-unsafe 区域可能继续存在
在 C/C++ 内部现代化 能在保留行为资产的同时改善 ownership、boundary 与验证 渐进降低风险,并可快速 rollback 规则与工具采用的完整性依赖 toolchain 与组织 discipline
用 Rust 编写新组件 新功能无需重新实现既有行为 不产生 rewrite regression 即可把 Safe Rust 默认值用于新代码 与既有 API、build、runtime 的集成成本
选择性用 Rust 替换高风险模块 缺陷风险集中在狭窄 interface 把保证收益集中到高风险部分 FFI/ABI 与 dual-language lifecycle 成本
全面或大范围重写 既有 architecture 本身阻碍需求,且规范、test oracle、过渡资源充足 同时重新设计 architecture 与 implementation model 最广泛的回归、cut-over、rollback、进度与组织风险

选择策略前,至少应明确以下问题。

  1. 缺陷模型: 实际要减少的是 use-after-free、data race 等 memory safety 问题,还是逻辑错误、可用性、性能或运行复杂性?
  2. 缺陷分布: 风险集中在新修改代码、特定 parser、driver、protocol boundary,还是均匀分布在整个系统?
  3. 规范与验证资产: 行为规范、regression test、corpus、fuzz target、benchmark 与 production telemetry 是否足以判断新实现?
  4. 边界与共存性: 模块 interface 是否足够狭窄,能够明确 ownership、lifetime、error、state 契约?
  5. 部署与 rollback: 是否可以部分 rollout、shadow/canary、回滚到旧实现,并维持 data/state compatibility?
  6. 性能与资源预算: 除 throughput 外,是否满足 tail latency、worst-case behavior、memory、code size、startup、energy 与 build/test 成本?
  7. 保证要求: 法规、threat model、assurance case 是否要求比 convention 和 detection 更强的语言级 prevention 或 formal proof?
  8. 组织与生命周期: 是否有人员和流程在过渡期或长期共存期内审查、调试、更新两种 toolchain 与两种语言?

不同答案可能使同一代码库中的不同策略都合理。Android 官方方法同时采用新 memory-safe code、既有 C/C++ hardening、interop,以及对高风险区域的选择性替换,就是一种混合策略案例。47 它并不是“渐进采用永远最好”的证据,而是证明全面重写并非改善 memory safety 的唯一途径的可能性证据

评价指标也不能停留在语言选择。目标缺陷的复发率与 severity、功能回归、tail latency 与 resource ceiling、build/test 时间、故障恢复时间、rollback 成功率、运行复杂性,以及 dependency 与 tooling 维护成本,都应在变更前后用相同定义测量。如果没有测量就断言“更安全”或“更易维护”,就又把语言保证与实际项目结果混为一谈。

3.3.5 主张分析:“唯一有意义的重构是用 Rust 重写”

下面这句话并非某个特定人物或 Rust Project 的直接引语,而是为了检验“C/C++ 中唯一有意义的改进就是 Rust 重写”这一论证结构而构造的合成分析命题

合成示例:“C/C++ 的重构就是用 Rust 重写,除此之外的重构毫无意义。”

如果把它当作一般命题,会产生以下问题。

  1. 范畴错误: 把保持可观察行为的 refactoring 与用新实现替换旧实现的 rewrite 定义成同一种工作。
  2. 虚假二分: 把维护与加固、同语言现代化、新 Rust code、选择性替换、大范围重写这些实际选择压缩成“放任”和“全面 rewrite”两项。
  3. 完美主义谬误(nirvana fallacy): 因为 C/C++ 工具与现代化不提供与 Safe Rust 相同的 memory-safety guarantee,就把缺陷检测、影响缩小和可维护性改善等局部效果也视为零。
  4. 混淆保证与结果: 容易把 Safe Rust 的语言契约与迁移后系统整体的 security、availability、correctness、maintainability 结果等同起来。
  5. 遗漏过渡成本: 把规范恢复、FFI/ABI、dual-language build、rollout、rollback、data/protocol compatibility 和组织学习排除在比较之外。
  6. 证据标准不对称: 如果要求 C/C++ 改进证明完全消除缺陷,却只凭 Rust 的语言保证就认为迁移后整个项目成功已被充分证明,就对两种策略使用了不同证据标准。

也必须避免反方向的普遍化。“只要把 C/C++ 现代化做得足够好,就没有理由迁移到 Rust”同样不普遍成立。 如果 memory-safety 缺陷是主要 threat,process 与 testing 无法把风险降到可接受水平,或者所需 assurance 要求更强的 prevention,那么 Safe Rust 的强制保证可以成为选择性替换或重写的重要理由。

中间结论

第 3.3 节的结论不是某种语言永远更优,而是必须把语言保证与变更策略分开评价。Safe Rust 在 sound 边界内提供预防特定 UB 与 data race 的强默认值,这与 C/C++ guideline、分析、testing 在保证层级上存在真实差异。另一方面,既有 C/C++ 的重构、现代化与加固也能在其他层次降低实际风险,在大型既有系统中可以与新 Rust 引入及选择性替换并用。

因此,维护、现代化、新 Rust 引入、选择性替换或全面重写中哪种策略合适,取决于缺陷模型、保证要求、既有行为资产、interface 与 testability、rollout 与 rollback 可行性、性能与资源限制、组织能力以及整个生命周期成本。如果不明确这些条件,“只有 Rust rewrite 才有意义”和“改进既有 C/C++ 就足够”这两个普遍命题都强于现有证据。

3.4 比较分析 2:Ada/SPARK 的数学证明与保证层级

本节的问题不是“Ada/SPARK 是否比 Rust 更安全”,而是:每种技术在什么阶段、什么条件下预防、检测或证明哪些属性,以及这些保证在哪里结束。要与第 3.2 节整理的 Safe Rust memory-safety contract 比较,就不能把 Ada 的类型、run-time check、异常处理,与 SPARK 的受限语言子集、flow analysis 和 proof 合并成一个单一的“安全层级”。

比较单位也必须分开。Safe Rust 的核心,是在 sound safe interface 内通过语言规则预防特定 UB 与 data race。Ada 提供 strong typing、language-defined run-time check、并发与同步结构,以及异常处理机制。SPARK 在 Ada 可分析的子集上增加限制与 contract,并使用 GNATprove 渐进地静态验证 flow property、run-time error 不存在性、integrity property 和 functional contract。51 这三种模型在保证的对象、时点、前提条件和成本上都不同。

Ada:运行时检测和异常处理并不等于自动恢复保证

Ada 2022 对 array index、scalar range、signed integer overflow、null access 等多种 language-defined condition 要求 run-time check;检查失败时会抛出 Constraint_Error 等异常。signed integer 的 overflow 与 modular integer 的有定义 wraparound 也有明确区分。异常发生后,当前执行序列的剩余部分会被放弃,控制转移到适用的 handler;如果局部没有 handler,则按语言规则继续传播。52

这与 C 的 unchecked memory access 相比,是一个重要的防御层。但“错误被检测为异常”和“系统完成恢复”并不是同一项保证。handler 是否安全恢复状态、只隔离失败 request、重启 task 或 process、保持 persistent state 一致,以及满足 deadline 与 failover 要求,都必须由程序和系统架构另行保证。Ada 的 exception mechanism 提供了表达并执行 recovery policy 的手段,但语言本身并不保证 service availability 或 mission continuity。

Ada 的 dynamic check 同样存在边界。Suppress 可以允许省略 language-defined check;如果执行进入本应使被抑制检查失败的情形,标准可以把该执行归类为 erroneous。Unchecked_DeallocationUnchecked_AccessUnchecked_Conversion,以及从外部 interface 进入的无效 access value 或 representation,也会产生独立的验证义务。52 因此,把 Ada 概括成“自动保证所有 memory error 都不存在”同样不准确。

SPARK:“可以使用形式化验证”与“整个程序已经得到证明”不同

SPARK 并不是完整 Ada,而是为了实现形式化分析而限制部分功能的语言子集。当前 SPARK User’s Guide 把 assurance level 区分如下。51

层级 主要验证目标 本节中的含义
Stone 检查代码是否属于有效 SPARK 子集 建立可分析语言边界,但不代表程序正确
Bronze 初始化与正确 data flow 静态消除 uninitialized read 与特定 parameter/global interference 问题
Silver Absence of Run-Time Errors (AoRTE) 在分析范围内证明不会发生导致 Constraint_Error、assertion failure 等意外异常的 run-time error
Gold 证明 key integrity property 证明显式声明的核心安全/完整性属性,例如 invariant 与 state transition
Platinum 形式化并证明 functional requirement 在 contract 足以表达功能需求的范围内,证明实现满足 specification

因此,“SPARK 以数学方式证明 run-time error 不存在”必须附带一个条件:分析范围和 proof obligation 实际上已经闭合。 Silver AoRTE 可以证明 division by zero、buffer/index error、overflow 等许多与 Ada check 对应的 run-time error 不会发生,但官方文档明确把 Storage_Error 排除在 SPARK 分析范围之外。Skip_ProofSPARK_Mode => Off 区域、外部 Ada/C/assembly code、imported data 与 hardware model 也需要单独的 assumption 或验证手段。53

并发:不存在 data race 与不存在 race condition 是两回事

Ada 本身提供 protected object、atomic/volatile object 等 shared-state synchronization 机制,但把它说成“在运行时自动阻止所有 data race”就过强了。Ada 2022 允许 task 在语言规则下读写 shared variable,并要求适当 synchronization;同时定义 atomic object 的 read/update 为 indivisible 等语义。52

SPARK 的 concurrent subset 更窄。在 Ravenscar 或 Jorvik profile 下,task 间共享被限制为 synchronized object,GNATprove 可以诊断 possible data race。Ravenscar 在单核条件下把 protected-object locking 限制为使用 Priority Ceiling Protocol 以防止 deadlock,GNATprove 还会检查 protected subprogram 中的 potentially blocking action 以及其他 tasking 限制。但官方 atomic counter 示例表明,即使没有 data race,两个 task 仍可能读取同一个值后互相覆盖,产生 lost-update race condition。要防止这类错误,需要 protected operation 或更强的 protocol invariant。54

当前 GNATprove 的 project-wide tasking analysis 也存在范围限制。分析使用当前处理 source file 直接或间接 with 的 unit context;官方文档指出,如果彼此不相连的 library unit 中的 task 访问同一 resource,某些 tasking check 可能因此被漏掉。54 因而,SPARK 文档化的 data-race 与 deadlock 保证必须连同支持的 profile、适用时的单核条件以及实际 GNATprove 分析 context 一起理解。第 3.2 节对 Safe Rust 也适用同样区分:预防 data race 并不等于证明 TOCTOU、错误 state transition、deadlock、starvation 等一般 concurrency defect 不存在。

证明边界:contract、assumption 与外部系统

GNATprove 的 modular proof 在分析 caller 时假定 callee 的 contract,在分析 callee body 时再验证该 contract。在现实系统中,如果整个程序并非全部作为 SPARK 分析,就可能保留对 non-SPARK Ada、C、assembly、device register、imported value、compiler 与 target behavior 的前提。SPARK 文档要求用 --assumptions 和单独 review 管理这些残余 assumption,并明确提醒,pragma Assume 等 assumption 可能把错误引入 verification process,因此必须谨慎论证。53

因此,解释 proof result 时至少应同时记录:证明了什么、分析了哪些 code scope、以哪些 contract 作为 specification、信任了哪些 assumption,以及如何验证外部环境和 compiler/runtime/hardware。针对错误或不完整 specification 的完整 proof,并不等于相对于真实需求的完整 correctness。

保证机制比较

属性 Safe Rust Ada SPARK 主要边界
memory access 与 lifetime 在 sound safe boundary 内静态预防特定 UB 执行 index/range/null access 等 language-defined check,但不提供一个笼统保证来排除所有 dangling-access lifetime error 可在受限 pointer/aliasing model 与 proof obligation 下静态证明相关 AoRTE Rust 的 unsafe/FFI、Ada 的 suppressed/unchecked operation、SPARK 外 code 与 assumption
数组边界 safe indexing 越界时 panic;unchecked access 属于 unsafe 边界 Index_Check 失败时抛出异常 可把“该 check 不会失败”作为 proof obligation 证明 未 proof 的 code 与外部输入 contract
整数 overflow 遵循第 3.2 节所述 profile/operation 特定 semantics,与 memory safety 分开 signed integer 在 overflow check 失败时异常,modular integer 使用有定义 wraparound 可在分析范围内把 overflow check failure 不存在证明为 AoRTE Storage_Error、独立 resource bound、external arithmetic assumption
data race 在 sound Safe Rust 中预防 提供 synchronization construct,但不自动检测或阻止所有 shared access 在支持的 concurrent subset 中静态排除 data race 一般 race condition 与 protocol bug 另行处理
general concurrency correctness 一般不保证 deadlock、livelock、starvation、TOCTOU 不存在 提供 protected/tasking mechanism,但 correct protocol 仍是设计责任 在支持 subset 中静态排除 data race,检查 Ravenscar 单核 deadlock 防止约束与 protected/tasking rule,并可分析显式 invariant lost update 等一般 race 与 liveness 另行处理;当前 project-wide tasking analysis 存在 context 范围限制
logical/integrity property 除 type system 表达的部分 invariant 外,一般功能正确性另行处理 可表达 contract 并动态检查 Gold/Platinum 可证明显式 integrity/functional contract 依赖 specification completeness 与 assumption
recovery 与 availability panic strategy 与 isolation/restart architecture 是独立问题 exception handler 可实现 response policy AoRTE 可消除特定 unexpected exception 均不会自动保证 service recovery、redundancy、deadline、resource ceiling
resource exhaustion 与 memory/resource safety 分开 Storage_Error 等是独立 failure mode Storage_Error 不在 SPARK analysis 范围内 需要 capacity planning、bounded allocation、admission control 等独立 invariant

这张表最重要的不是把某一列换算成单一分数。Safe Rust 的优势,是用相对较少的 specification annotation,把特定 memory-safety invariant 强制为普通代码的默认约束。Ada 通过类型、dynamic check、exception、tasking abstraction 提供不同防御层。SPARK 则接受更受限的语言、显式 contract 与 proof effort,以换取把静态 proof 从 AoRTE 扩展到 key integrity property 与 functional requirement 的能力。

性能、实时与生命周期成本

保证机制放置在哪一层,也会影响性能与维护成本。Ada run-time check 在执行过程中提供检测,因此必须评估其时间成本以及对目标 workload 的 worst-case execution time 影响。在 SPARK AoRTE 实际完成的范围内,GNAT/SPARK workflow 可以把 proof 作为生成移除相应检查 executable 的依据,但这不意味着“proof 没有成本”。官方文档说明,大型程序的 proof 可能耗时数小时;loop invariant、contract、manual proof 与 justification 都会带来维护成本;Platinum 层级的 full functional proof 并不常见,通常只应用于较小范围。51

因此,在大规模和极限环境中,比较不能只看 runtime overhead,还要纳入 proof latency、CI 资源、incremental verification 能力、contract 变更的传播范围、external assumption 的寿命、toolchain qualification、worst-case timing、memory ceiling 与 failure containment。强静态 proof 即使能消除特定 run-time check 成本,也不会自动解决 resource exhaustion、hardware fault、错误需求或运行恢复。

中间结论

Ada/SPARK 比较所揭示的,并不是“Rust 位于 C/C++ 与 SPARK 之间某一点”的简单安全排序。更准确的结论是:安全保证具有多个维度,不同语言以不同成本处理这些维度中的不同部分。

Safe Rust 的强项,是在 sound safe boundary 内默认预防特定 UB 与 data race。Ada 通过 strong typing、language-defined run-time check、exception 与 synchronization mechanism 来结构化错误检测和响应。SPARK 在可分析子集与显式 specification 的前提下,可以把静态 proof 扩展到 AoRTE、integrity property 与 functional contract。反过来,SPARK proof 也不会自动跨越 Storage_Error、non-SPARK code、external system 与 assumption,以及 specification completeness 的边界。

因此,“Rust 只要能编译就安全”“Ada 有异常所以恢复有保证”“SPARK 保证整个程序在数学上正确”这三句话都省略了必要条件,属于过强概括。真正应比较的不是语言名称,而是要保证的属性、保证范围、失败条件、验证成本、运行时成本,以及整个系统中仍然存在的 proof obligation

3.5 比较分析 3:重新评价替代性内存管理方式(GC)

本节的问题不是“GC 是否比 Rust 慢”或“GC 语言是否不适合系统编程”,而是自动内存回收与基于所有权/生命周期的管理分别减少哪些缺陷,又各自留下哪些运行时、资源、开发和运维成本。与第 3.2 节一样,必须把语言保证、内存回收方式、具体运行时实现以及实际 workload 中观测到的结果分开。

GC 与 memory safety 不是同一个概念

Tracing GC 的直接作用是从 root 出发跟踪可达(reachable)对象,并让 managed heap 中已经不可达的内存重新可用。GC 管理的对象不需要手工 free,因此在 managed 区域内,它是减少 premature free、再次使用已释放对象等错误类型的强力机制。然而,garbage collection 是内存回收策略,本身并不等于整个语言的 memory-safety 定义。 bounds/type check、native/unsafe code、FFI、逻辑错误、并发 protocol 与 resource exhaustion 依赖另外的语言、runtime 和系统规则。55

Reachability 也不等于“应用程序已经不再需要”。如果 global cache、collection、event registration 等 root 继续引用对象,tracing GC 会正确地把该对象视为 live,因此不会回收。

即使使用 GC,错误 retention 仍可能让 heap 持续增长直至 OutOfMemory。file descriptor、socket、lock、memory mapping 等非内存资源也不能仅凭 GC 的 reachability 就假定会在期望时刻释放。

Go 的 runtime.AddCleanup 文档明确指出,cleanup 可能在对象不可达后任意延迟执行,而且不保证在程序退出前执行。.NET 文档则建议为封装 unmanaged resource 的对象提供 Dispose 等显式清理路径。因此,如果 release 时点本身属于 correctness 的一部分,就不应只依赖 GC reachability 或 cleanup/finalizer 来管理该资源。55

“现代 GC”也不存在单一的 latency/throughput 特性

如果把 GC 当成一种实现,概括为“因为 Stop-the-World 所以慢”,或者反过来说“现代 GC 已经解决 pause 问题”,都会丢失真实的设计空间。同一 runtime 可能同时提供 serial、parallel、generational、mostly-concurrent、fully-concurrent collector 或不同 latency mode,collector 实现本身也会随 release 改变。例如 Go 1.26 已把此前属于 experimental 的 Green Tea collector 切换为默认值。56

当前 Java SE 26 HotSpot 官方文档明确展示了这些差异。默认 G1 在追求高 throughput 的同时,被设计为以高概率满足 pause-time goal;ZGC 则被描述为把最大 pause 保持在 1ms 以下的 low-latency collector,但以部分 throughput 为代价。Oracle 也限定 collector 选择取决于 heap 大小、live data、CPU 与 workload。这个案例是反驳“所有 GC 都有长暂停”的强反例,但不能据此把 ZGC 的数字推广成其他 collector 或 runtime 的普遍属性。56

Go 官方 GC 指南同样通过 GOGC 与 memory limit 说明 memory 与 CPU 的 trade-off,而不是只谈 throughput。如果把 memory limit 设得过于接近 live heap,GC 可能过于频繁地运行,造成 thrashing 和严重的进展下降,因此 Go 将 memory limit 定义为 soft limit,而不是 hard limit。即使大部分 tracing 与 application 并发执行,短暂的 stop-the-world transition、GC CPU scheduling、mutator assist、write barrier、root scan 等 latency 来源仍然存在。56

.NET 也记录了同类 trade-off。low-latency mode 通过抑制部分 collection 来减少 pause 介入,但 managed heap 可能变大,fragmentation 也可能增加;发生 memory pressure 时仍可能重新执行 collection。因此,降低 latency 的策略并不是独立于 CPU、memory、fragmentation 与 failure risk 的免费优化。56

必须区分低 pause 与 hard real-time 保证

ZGC 文档化的 1ms 以下最大 pause,可以成为 low-latency 系统的重要工程选项。但短 GC pause、p99 latency 或 pause-time target,与证明满足 hard real-time deadline 不是同一个命题。 G1 把 pause-time goal 表述为概率性目标;.NET low-latency mode 在 memory pressure 下仍可能发生 collection;Go 文档也在 GC pause 之外单独列出 concurrent GC CPU 占用、mutator assist 等会影响 end-to-end latency 的因素。57

反过来,把“只要存在 GC,hard real-time 就从根本上不可能”一般化,也不是这些资料所证明的结论。real-time 适用性取决于完整执行模型,包括具体 collector 的 scheduling、allocation、barrier、pause bound、heap policy、OS scheduler、hardware 与 workload。普通的 low-pause 目标或平均值、percentile 测量不能被视为 hard deadline 的保证。Rust 没有 tracing GC,确实消除了一类波动来源——tracing pause 与 tracing CPU——但语言并不会自动消除 allocator、page fault、I/O、lock contention、destructor work 或 scheduler 导致的 deadline miss。

Rust 与 tracing GC 的成本不能只分成“开发者时间”和“机器时间”两格

过去“Rust 花开发者时间,GC 语言花机器时间”的比喻可以解释一部分成本转移,但作为比较模型过于简单。Rust 同样可能存在 heap allocator、Drop、reference counting、atomic operation、locking、cache behavior 等运行时成本;GC 语言也要为 heap sizing、allocation-rate 管理、profiling、tail-latency tuning、deterministic resource release 支付开发与运维成本。反过来,tracing GC 可以自动回收复杂 object graph 与 cycle,降低显式表达 lifetime 的负担;Rust 则可以在普通 scope/ownership 边界中更直接地表达 resource lifetime。

比较维度 以 Rust ownership/lifetime 为中心的管理 以 tracing GC 为中心的管理 需要确认的边界
managed memory 回收 容易把 ownership 结束与 Drop 直接连接到回收时点 按 reachability 与 collector cycle 自动回收 Rust 的 Rc cycle、故意 leak、abort;GC 的 retained root 与 delayed collection
use-after-free / double-free 在 sound Safe Rust boundary 内静态预防 reachable 的 GC-managed object 不会被回收,从而减少 managed heap 中此类错误 Rust unsafe/FFI 与 managed runtime 的 native/unsafe boundary 仍需单独处理
cyclic object graph 可能需要 Rc/Weak、arena、index 等额外结构 unreachable cycle 也可由 tracing 回收 仍 reachable 但已无用的 cycle/cache,GC 也不会回收
latency 没有 tracing pause、write barrier、GC thread,但 allocator、drop、scheduler 成本仍在 各 collector 的 pause、concurrent work、barrier、mutator assist 不同 在实际 workload 中测量 end-to-end tail latency 与 worst case
CPU / throughput 没有 heap graph tracing 成本,但存在 allocator、drop、refcount、synchronization 成本 tracing、barrier、GC worker 消耗 CPU,collector 会在 latency 与 throughput 之间交换 不从平均 throughput 单独推导 tail latency 或 energy
memory footprint 不要求 GC 专用 heap headroom,但仍有 allocator fragmentation 与 working set live set 之外还需要 allocation headroom 与 GC metadata,footprint 随 tuning 改变 用同一定义测量 RSS、peak committed memory、fragmentation、OOM/thrashing
非内存资源 在正常 lifetime 中可用 Drop/RAII 结构化 release GC reachability 本身不保证 release 时点,可能需要 explicit close/dispose abort/process death/external resource semantics 在两边都需另行处理
hard real-time 没有 tracing GC 本身并不保证 deadline low-pause collector 本身并不保证 deadline 纳入 WCET、allocation policy、scheduler、page fault、I/O 与 failure containment

大规模与极限环境的评价标准

因此,比较 GC 与 Rust 不能只比较单个 benchmark 的平均 throughput 或一个 GC-pause 数字。至少应在相同 workload 与部署条件下测量allocation rate、live-set 大小及变化、object graph 的 pointer density、heap headroom 与 RSS、GC/allocator CPU、p50/p99/p99.9 与最大 pause、end-to-end tail latency、throughput、peak memory、OOM 或 thrashing、startup、resource-release 延迟、deadline miss、observability/tuning 成本以及长期运维成本。collector 或 compiler 版本变化后,也应重新确认这些测量是否仍然有效。

中间结论

第 3.5 节的结论既不是“现代 GC 足够快,所以 Rust 的优势消失”,也不是“GC 因为 pause 而不适合系统编程”。当前 collector 具有不同的 latency、throughput 与 memory 特性,也存在 Java ZGC 这样明确以极低 pause 为目标的实现。同时,Go 与 .NET 文档也显示,降低 latency 的过程伴随 CPU、heap headroom、collection frequency、fragmentation 等额外成本与失败条件。

Rust 的强项,是在没有 tracing GC 的情况下,在 sound Safe Rust boundary 内静态预防特定 memory-safety 错误,并能显式结构化 resource lifetime。GC 环境则可以自动回收 managed object graph,并简化复杂共享与循环结构的 lifetime 管理。哪一种更合适取决于所需 memory-safety boundary、latency 与 deadline、allocation pattern、live set、memory ceiling、native/FFI 比例、非内存 resource lifetime、开发与运维能力以及总 lifecycle cost。不说明这些条件时,“GC 很慢”和“有 GC 就解决了 lifetime 问题”这两种一般化都强于当前证据。

3.6 话语分析:“实用性”与“责任”的重新定义

前述第 3.1–3.5 节从技术层面比较了 Rust 的概念先例、Safe Rust 与 unsafe 的保证边界、变更策略、Ada/SPARK 以及 tracing GC。第 3.6 节的问题不是重新证明这些技术结论,而是考察:当有条件成立的技术命题在公开话语中被转换为关于实用性、责任、优越性以及开发者地位的判断时,增加了哪些推理步骤。这正是研究问题 5(RQ5)所处理的问题。

分析首先区分资料层级。Rust Project 的官方文档与 Rust Reference 用作确认项目公开目标和语言保证边界的一手资料。Reddit、Rust Users Forum、博客等公开帖子,只用作说明某种论证形式确实可能出现的定性案例。本书目前使用的公开案例既不是概率样本,也不是预先定义的代表性 corpus,因此本节不会从中推导“Rust 社区通常如何”或“大多数 Rust 用户如何”这类频率与代表性命题。58

Rust Project 自身的公开说明也有助于确认这一区分。当前官方网站把 Rust 描述为让每个人都能构建 “reliable and efficient software” 的工具,官方仓库介绍则分别列出 performance、reliability 与 productivity。因此,生产力、工具与可接近性属于 Rust 的官方价值主张,但这本身既不能证明 Rust 首次发明了各项基础概念,也不能证明它在所有领域都更优越。59

3.6.1 “实用创新”的话语功能

第 3.1 节的历史分析与“Rust 是一种实用创新”这一评价并不必然矛盾。概念新颖性(conceptual novelty)对既有概念的集成、默认化、工具化和推广(engineering integration and adoption)是不同的评价轴。即使 ownership、RAII、affine/linear 系思想和静态验证都存在先例,把语言、编译器、Cargo、诊断工具与库生态整合为统一开发体验的工程成果,仍然可以单独评价。

公开讨论中也能看到使用 “democratization” 一词的案例:借助现代工具和抽象,Rust 被认为降低了进入过去高度依赖 C/C++ 知识的领域的门槛。同一讨论中也可能同时出现反论,指出在生态成熟度、团队熟练度或变化频繁的领域占主导时,其他语言可能更具生产力。这类案例所能证明的是这样的论证形式与反论确实存在于公开话语中,而不是哪一方代表社区多数意见。58

因此,“实用创新”需要区分以下问题。

问题 所需证据 “实用创新”能够回答的范围
这一概念是否由 Rust 首创? 语言、论文、标准与实现的历史 不能直接回答
Rust 是否把先行概念集成为更易使用的形式? 语言设计、工具、DX、生态与采用案例 可以直接评价
对特定组织或产品而言是否更实用? workload、人员、性能、assurance、迁移与运维成本 可以有条件地评价
是否在所有系统中都更优越? 支撑全部主张适用范围的比较证据 有限案例无法回答

如果面对“概念上是否新颖?”这一问题,只回答“它被广泛使用而且实用”,却隐去评价标准已经改变这一事实,那么论点发生了转移。反过来,如果明确说明“概念发明之外,集成与推广本身具有工程创新”,这就不是回避问题,而是另一评价轴上的正当主张。无论这一划分对 Rust 有利还是不利,都应采用同一标准。

3.6.2 “责任”的归属:内存泄漏与 unsafe 的讨论方式

分析责任时,首先必须区分语言不保证的事情对系统不重要的事情。Rust Reference 并不把 memory/resource leak 或 destructor 未执行归类为 unsafe。标准库的 mem::forget 也是 safe 函数,其文档解释说,这是因为 Rust 的 safety guarantee 本身不保证 destructor 一定执行。因此,“leak 不违反 Safe Rust 的 memory-safety guarantee”这一表述符合官方保证边界。60

但不能由此推出“所以 leak 不重要”或“所以全部责任都属于应用开发者”。在长时间运行的服务中,retained object 或 resource leak 可能导致 OOM、file-descriptor exhaustion、latency 上升、重启以及可用性下降。这些属于不同于 memory-safety 定义的运行属性。公开 Rust 讨论中也同时存在“safe code 可能发生 leak”的说明与“这种 leak 在真实服务中可能成为严重资源问题”的讨论。这是 guarantee boundary 与 operational severity 属于不同评价轴的定性案例。58

unsafe 简单描述成“关闭编译器检查的代码”,或描述成“发生问题时把责任隔离到编写者的标记”,同样不准确。Rust Reference 把 unsafe 描述为创建或解除(create or discharge)证明安全性的义务(proof obligation)的关键字unsafe fnunsafe trait 等定义必须在其他位置满足的附加 safety condition,而 unsafe {}unsafe impl 等属于程序员声明相关 safety condition 已被满足的一侧。更重要的是 soundness 边界:Reference 明确把“内部 unsafe 实现使 safe client 能够触发 UB”的抽象定义为 unsound60

因此,对于库内部的 unsafe 缺陷,应区分以下责任层级。

层级 应当询问的问题
语言与编译器保证 是否超出了 Safe Rust 静态规则所承诺的范围,还是某项外部 proof obligation 被错误解除?
unsafe abstraction 的 soundness safe caller 是否可以在不违反任何已文档化附加条件的情况下触发 UB?
库与 API 责任 invariant、safety contract、review 与 test 是否充分?
应用与运维责任 dependency 管理、隔离、观测、资源上限、更新与事故响应是否充分?
组织与 lifecycle 责任 是否定义了高风险边界的 owner、audit 周期以及 toolchain 与供应链验证?

在这一框架下,“Safe Rust 的语言规则本身没有直接失败”和“提供 safe API 的库存在 soundness 缺陷”可以同时成立。公开的 unsafe 缺陷讨论中,也有案例围绕这样的问题争论责任位置:真正出现 UB 的 unsafe operation 与破坏其所依赖 invariant 的 safe code 可能相隔很远。这只是说明责任并不必然简单隔离在某个 unsafe 块中的定性案例,并不能证明这种结构出现的频率。58 反过来,由一个 unsafe 缺陷概括出“Rust 整个 memory-safety 模型都没有意义”,同样属于过度一般化。责任不能靠一个词整体转移,而应沿着保证边界与契约边界分解

3.6.3 区分有条件的工程优势与普遍地位判断

RQ5 最重要的边界,是从技术命题转向关于人或技术整体地位的命题这一阶段。下面前三个步骤在各自拥有充分证据时,都可以构成工程结论。

  1. 在 sound Safe Rust 边界内,仅由 safe client 不能引发 undefined behavior,而 data race 属于 Rust 所归类的 undefined behavior。60
  2. 对某个特定系统而言,这类缺陷风险很高,而采用 Rust 的成本可以接受。
  3. 因而对该系统而言,Rust 可能是强有力的采用候选,或者是更好的选择。

如果从这里直接跳到“所以 Rust 在所有系统中都更优越”“其他语言已经过时”或“做出不同选择的开发者缺乏能力、资格或责任感”,就需要完全不同的证据与规范性前提。能够防止某一缺陷类别的语言属性,并不会自动决定 workload、既有资产、hard-real-time 要求、生态适配、人力、迁移风险与 lifecycle cost;有条件的技术选择也不是衡量开发者智力或道德价值的指标。

这一标准是对称的。依据 borrow checker 的成本、unsafe 边界缺陷或生态不足,就推出“Rust 对任何系统都不适用”,或者贬低 Rust 用户的能力,也属于同类过度一般化。本书分析的对象不是某种语言群体的高下,而是有条件技术命题如何失去适用范围,并被转换成普遍的技术或社会地位命题这一推理过程

在大规模与极限环境中,这一区分不只是修辞礼仪。真实事故响应必须具体指定 defect locus、proof obligation、API contract、dependency owner、部署与 rollback、resource ceiling、audit 和 incident ownership。“语言不保证”不会消除运维责任,“这是开发者责任”也不能替代对验证、观测与恢复流程的明确规定。准确分解责任是安全性、可靠性、可维护性和长期 lifecycle cost 的组成部分。

中间结论

第 3.6 节的结论并不是否定 Rust 的实用性,也不是把所有 unsafe 问题都归为语言自身失败。“实用创新”可以作为区别于概念发明、用于评价集成与推广成果的有效轴。memory/resource leak 位于 Rust 的 memory-safety guarantee 之外,这一说明在技术上也成立。unsafe 同样是把外部 proof obligation 显式化的重要设计机制。

与此同时,这三个事实分别都不意味着已经证明概念原创性、已经证明运行上无害、或已经消除系统责任。RQ5 的分析标准是:区分官方文档与公开话语案例,不从定性案例推断频率,并明确从技术保证跳到普遍优越性或开发者地位判断所需的额外前提。当前确认的公开案例说明这些论证形式确实存在,但不能证明它们代表 Rust Project 整体或 Rust 用户群体的态度。58

3.7 结论:性能、安全性与生产力的权衡

第 3 章不能以把 Rust 与替代方案依次放在单一“性能—安全性—生产力”三角形上的方式收尾。前面的分析表明,需要同时考察:希望减少哪类缺陷、要求哪种保证且保证延伸到什么边界、这些保证来自静态规则、动态检查、自动回收还是形式化证明,以及这种选择把运行时、验证、迁移和运维成本放到了哪里

因此,比较语言与生态系统时,至少应当分开以下六个轴。

  1. 缺陷模型与保证范围: use-after-free、double-free、data race、一般 race condition、逻辑错误、resource exhaustion、availability failure 中,哪些需要预防、检测或缓解?
  2. 保证机制: 如何组合语言与类型系统的静态 prevention、run-time check 与 exception、tracing GC、contract 与 formal proof,以及 sanitizer、static analysis、fuzzing 等检测手段?
  3. 执行成本与资源特性: throughput、tail latency、worst-case timing、allocator/GC CPU、memory headroom、code size、startup、synchronization 与 resource-release 成本在目标 workload 中如何表现?
  4. assurance 与实时要求: 哪些属性必须 proof?信任哪些 assumption 与外部 code?如何证明 hard deadline 与 failure containment?
  5. 变更策略与既有资产: 在保留与 hardening、同语言 modernization、新组件采用、选择性替换和全面 rewrite 之间,需要多大范围的变更?
  6. 组织与生命周期成本: 组织能否承担学习、code review、build/test、proof 与 CI、dependency 与 toolchain、observability、部署与 rollback、招聘及长期维护?

沿这些轴观察,各种方法的区别不是一个总分,而是不同的保证与成本配置

方法 优势出现的条件 仍然存在的主要边界与成本
C/C++ 既有资产、生态系统和低层控制很重要,并且能够渐进采用 RAII、smart pointer、guideline、static analysis、sanitizer 与 hardening 语言默认并不会静态阻止所有 memory-unsafe access;规则与工具的覆盖范围和完整性、legacy boundary 与验证 discipline 仍需单独管理
Go、Java、C# 等 tracing-GC 环境 workload 重视 managed object graph 的自动回收,以及降低复杂共享与循环结构中显式 lifetime 管理的负担 collector 特定的 latency/CPU/memory 权衡、retained object、native/unsafe boundary、非内存资源的显式 release 与 hard-real-time 证明仍是独立问题
Ada 需要 strong typing、language-defined run-time check、exception、tasking abstraction 与明确控制流 仍有 check suppression、unchecked operation、external representation 等边界;检测本身不等于 recovery 或 availability 保证,也必须评估 run-time check 的 timing cost
SPARK 值得接受受限语言 subset 与 contract/proof effort,把 proof 范围从 AoRTE 扩展到明确写出的 integrity property 与 functional requirement 保证范围仍受 assurance level、code scope、specification completeness、Storage_Error、non-SPARK 与 external code、assumption,以及 proof/CI 维护成本限制
Rust 在没有 tracing GC 的情况下同时需要低层控制以及 sound Safe Rust 边界内的 memory-safety 与 data-race prevention,并且能够把 ownership/lifetime 关系结构化到类型和 interface 中 unsafe、FFI、library/compiler correctness、一般 race condition、logic、availability 与 resource bound 仍是独立问题;allocator、Drop、refcount、atomic、locking 等运行时成本,以及学习、编译和集成成本也仍然存在

这张表不是为了给“哪种语言最安全或最快”排序。正如第 3.4 节所示,Safe Rust 默认的 memory-safety invariant 与 SPARK 的显式 contract proof 属于不同种类的保证;SPARK 的 Gold/Platinum 等 assurance objective 也不会自动超出 specification 与 assumption 的范围。正如第 3.5 节所示,tracing GC 自动化 managed memory 回收,但具有 collector 特定的资源与 latency 特性;不能把这些成本简单称为“机器时间”,同样也不能把 Rust 的成本简单归结为“开发者时间”。

语言选择与变更策略不是同一个决定

第 3.3 节的重要结论是,目标语言的保证很强,与既有系统应当改变多少,是两个不同问题。为了减少特定缺陷,一个 C/C++ 系统内部可以组合保留与 hardening、modernization、新 Rust component、高风险模块的选择性替换、bounded rewrite 和大范围 rewrite。Rust 的 memory-safety 优势不会自动证明所有 legacy code 都应全面重写;反过来,仅仅存在 migration risk 也不足以排除在新增或高风险区域采用 Rust。

变更的净效果必须在同一标准下比较减少的缺陷风险与新引入的迁移风险。规范恢复、test oracle、FFI/ABI、data 与 protocol compatibility、dual-language build、rollout 与 rollback、performance regression、运维成熟度和组织能力,都应与语言保证一起评价。从这个角度看,“用不用 Rust”不如“通过哪种策略改变哪一条风险边界”这个问题准确。

安全性不是单一轴,技术选择也不是地位判断

第 3.2 节和第 3.4 节的比较表明,memory safety、security、functional correctness、concurrency correctness、availability、resilience 与 real-time assurance 可以彼此相关,但不是同一种属性。一种语言在一个维度提供强保证,并不意味着其他维度的保证会自动随之产生。因此,“能编译就安全”“有异常就保证恢复”“证明过所以整个系统都正确”“有 GC 就解决 lifetime 问题”等说法,都必须检查适用条件与边界。

第 3.6 节的话语分析把同一原则用于技术选择。有条件成立的工程优势,在相关条件与成本具有充分证据时,可以支持强有力的采用决策;但这本身既不能建立对所有系统都成立的普遍优越性,也不能成为判断选择其他方案的开发者能力、资格或责任感的依据。对于反方向的过度一般化,也应采用相同证据标准。

大规模与极端环境中的最终评价标准

在大规模、长期运行、关键任务与 hard-real-time 环境中,仅凭平均 benchmark 或某种语言的一项代表性特征不足以下结论。

至少需要在实际 workload 与部署条件下,同时测量或证明目标缺陷的发生率与 severity、tail latency 与 worst-case timing、throughput、CPU budget、code size 与 storage budget、peak memory 与 resource ceiling、energy/power budget、OOM 或 thrashing、deadline miss、failure containment 与 recovery、startup、build/test 与 proof latency、CI 资源、dependency/supply-chain/toolchain 验证、observability、rollout 与 rollback、incident response、人力以及长期 lifecycle cost

如果 compiler、collector、proof tool、dependency、hardware 或 workload 发生变化,也应重新确认原有结果是否仍然有效。

本章结论

第 3 章的结论不是用一个综合分数给特定语言排序。Rust 是重要的工程选项,因为它能够在 sound Safe Rust 边界内默认阻止特定 UB 与 data race,同时在没有 tracing GC 的情况下维持低层控制。C/C++ 可以保留既有资产和低层控制,并渐进采用 hardening 与 modernization。tracing-GC 环境可以自动回收 managed memory 与 unreachable cycle,从而降低复杂 object graph 的 lifetime 管理负担。Ada 提供 strong typing、language-defined run-time check、exception 等防御层;SPARK 则可以在受限 subset 和显式 contract 的基础上,把 proof 范围从 AoRTE 扩展到 integrity property 与 functional requirement。

哪种选择更合适,取决于缺陷模型、所需 assurance level 与边界、workload 与 real-time 约束、resource ceiling、既有资产与变更范围、验证资产、interop、部署与恢复策略、生态系统、组织能力以及总 lifecycle cost。把这些条件明确出来,并用相同证据标准比较替代方案,才是本章所说的工程结论。

4. 重新评价所有权模型及其设计哲学

第 4 章不把 Rust ownership 写成“某个概念最初在哪里被发明”的单一起源叙事。首先,第 4.1 节把 C++ 的 RAII、smart pointer、move semantics 与 Rust ownership 之间的文档明确的直接影响、历史先例、概念相似性以及标准化年代分开讨论。第 4.2 节再与这些先行技术比较,分析 Rust 如何把 ownership、move 与 borrowing 规则放入类型系统和编译器检查。最后,第 4.3 节与 Ada/SPARK 的 contract-based verification 比较,考察不同保证机制在特定数据结构和 workload 中造成哪些约束与成本。历史影响关系本身并不能证明今天的保证强度、性能、安全性,或某项技术对特定项目的适合程度。

4.1 Rust 所有权与 C++ RAII、智能指针的历史关系

本节沿用第 3.1 节的历史归属标准。两种技术相似,可以说明概念相似性,但仅凭相似不能证明直接谱系。反过来,如果官方资料明确列出某种影响,则可以在该范围内称为文档明确的直接影响。Rust Reference 把 C++ 的 references、RAII、smart pointers、move semantics 列为 Rust 设计的影响,同时也把 ML Kit 与 Cyclone 的 region-based memory management 作为其他影响单独列出。33 因此,本节的问题不是“ownership 这一一般概念是否由 C++ 首先发明”,而是哪些 C++ 资源管理技术可以确认对 Rust 产生了影响,以及两者的规则和强制位置在哪些地方相同、哪些地方不同

C 的手动内存管理是问题空间的背景,而不是谱系证据

C 的 malloc()free() 让程序员显式控制动态内存的分配与释放。lifetime 配对错误可能产生 memory leak、double free、use-after-free 等问题。这一事实说明了 RAII、smart pointer、ownership system 等技术所处理的问题空间,但它本身并不能证明某一种技术是另一种技术的直接祖先。

  • memory leak: 已经不再需要的 allocation 没有释放而继续保留,可能增加内存使用和长期运行时的 resource pressure。
  • double free: 同一 allocation 被释放两次,可能破坏 allocator state 或导致 undefined behavior。
  • use-after-free: 已结束 lifetime 的 storage 被再次使用,可能造成 memory corruption 或 security vulnerability。

即使都归入“手动管理”这一大类,这三种错误的原因和保证边界也不同。某个语言功能减少其中一种错误,并不自动保证 logical correctness、availability 或 resource bound。这一区分延续第 3.2 节和第 3.7 节已经确立的安全边界。

C++ RAII:把资源释放与 scope、object lifetime 绑定的先行技术

C++ 的 RAII 把资源取得与释放绑定到 object lifetime。C++ Core Guidelines 建议通过 resource handle 和 RAII 自动管理资源,并把负责释放资源的 entity 视为 owner。Rust Book 同样说明值离开 scope 时通过 drop 清理资源的行为,并明确把 C++ RAII 作为比较对象。33 因此,说RAII 与 Rust 中绑定于 scope/object-lifetime 的 resource cleanup 在历史和概念上存在联系是有根据的。

但这里的证据不足以把这种联系扩大成“ownership 这一一般概念最早在 C++ 中确立”的主张。Rust ownership 除了 scope 结束时的 cleanup,还结合了值 move 之后限制继续使用旧 binding 的规则、shared/mutable borrowing 规则,以及对这些规则的 compiler checking。Rust Reference 还把 ML Kit 和 Cyclone 列为 C++ 之外的影响,这也构成了不能把 Rust 的 memory/lifetime 设计归约为单一 C++ 谱系的边界。33

把智能指针的标准化年代与语义比较分开

“智能指针是在 C++11 才首次引入”的说法也不准确。C++ 标准库在 C++11 之前已经有 auto_ptr;WG21 资料记录,加入 unique_ptr 并把 auto_ptr 标记为 deprecated 的方向在 2007 年获得接受。2011 年的 C++ 标准化资料已经把 unique_ptrshared_ptr 包含在 C++11 时代的标准库设计中。61 因此,这里把特定 smart pointer 的存在时间和标准化过程与其是否直接影响 Rust 的主张分开处理。

现代 C++ 中两种有代表性的 ownership 表达,适合与 Rust 做语义比较。

  • std::unique_ptr 表达 exclusive ownership,通过 move 而不是 copy 转移 ownership。C++ 的 move construction 之后,source unique_ptr 仍然是一个对象,但不再拥有该 pointer;而 Rust 的 non-Copy 值在整个值被 move 后,旧 binding 的继续使用会被静态拒绝。两者都把 ownership transfer 与 copy 区分开来,但 moved-from state 的规则并不相同;这种相似性也不能证明 unique_ptr 是整个 Rust ownership 的直接原型。62
  • std::shared_ptr 通过 reference counting 表达 shared ownership。Rust 的 Rc<T>Arc<T> 同样提供 reference-counted shared ownership,因此适合作为比较对象。不过,本节使用的资料不能证明 shared_ptrRc<T>Arc<T> 之间存在“直接基础”式的一对一谱系。62

关键差异不只是这些工具是否存在,而是规则在哪里适用,以及默认边界是什么。C++ 可以大量使用 RAII 和 standard smart pointer,同时仍使用 raw pointer、manual allocation 与 custom lifetime protocol。Rust 则把 move 与 borrowing 规则纳入 Safe Rust 的默认值 semantics:compiler 会静态拒绝 use-after-move、相互冲突的 shared/mutable borrow 等模式,而 unsafe 在该边界之外引入另外的 safety obligation。与其简单说“一边靠纪律、另一边靠安全”,更准确的比较是:哪些规则默认被强制,哪些 escape hatch 与 proof obligation 仍然存在

中间结论

Rust Reference 直接记录了 C++ 的 RAII、smart pointers、move semantics 对 Rust 的影响。同时,官方资料也记录了 C++ 之外的影响,包括 ML Kit 和 Cyclone。因此,“C++ 与 Rust 之间存在历史影响”和“ownership 概念本身起源于 C++”是两个不同命题。unique_ptr 与 Rust move/ownership、shared_ptrRc/Arc 的比较有助于解释设计差异,但不能仅凭相似就推断一对一谱系。

这一历史整理也不决定今天的工程优劣。哪一种模型更合适,需要分别评估 memory-safety guarantee、unsafe/FFI boundary、concurrency model、allocator 与 reference-counting cost、latency 与 resource ceiling、existing codebase、migration risk、verification assets 以及 lifecycle cost。下一节 4.2 因而把这种历史关系作为背景,但分析 Rust 的实际差异时,关注的是规则如何组合以及 compiler enforcement 位于何处,而不是谁最先发明了概念

4.2 Rust 所有权规则的强制位置与保证边界

第 4.1 节区分了历史影响与概念相似性,因此这里要问的并不是“C++ 中是可选、Rust 中是强制吗”这样的二分法。更准确的问题是:什么属性在哪一层接受检查,该检查在什么前提和边界下提供保证,以及哪些责任仍然留给库、开发者和运行环境

ownership、move 与 borrowing 的强制位置并不唯一

Rust Book 把 ownership 描述为管理 Rust 程序内存方式的一组规则,并说明编译器会检查这些规则,拒绝违反规则的程序。non-Copy 值的 assignment 或函数传参可能发生 ownership move;整个值 move 后再次使用原 binding 会被静态拒绝。reference 与 borrowing 还受额外规则约束,编译期会检查 reference validity 以及相互冲突的 shared/mutable borrow。63

不过,把这扩大成“Rust 中所有与 ownership 相关的规则都由 borrow checker 在编译期强制”同样不准确。例如 RefCell<T> 通过 safe API 提供 interior mutability,同时把部分 borrowing rule 放到运行时检查borrow()borrow_mut() 遇到冲突 borrow 时会 panic,而 try_borrow()try_borrow_mut() 会把同样的冲突作为 Result 错误返回。因此,run-time checking 本身还要与把违规处理为 panic 的特定 API 区分开来。在 Rust 内部,同一设计目标可以分别由静态 type/borrow checking、library abstraction 与 run-time check 在不同位置承担。64

属性或机制 主要强制/检查位置 剩余边界
ownership 与 move type system 与 compiler check logical correctness、resource policy、外部系统状态另行处理
shared/mutable reference borrow checking 与 reference validity rule raw pointer、UnsafeCell、unsafe abstraction 的条件另行处理
RefCell<T> borrowing safe API 内部的 run-time check borrow()/borrow_mut() 冲突时 panic;try_borrow()/try_borrow_mut() 返回错误;recovery 与 availability 另行处理
unsafe contract/operation compiler 限制 unsafe 的使用位置和形式;compiler 无法验证的 safety condition 由作者负责满足 防止 UB 与 safe-client soundness obligation 仍然存在
Result 处理与 panic policy library API 与 application control flow 可恢复性、故障隔离、availability 属于 application/operation 设计问题

unsafe 不是关闭所有安全检查的模式

Rust Reference 把 unsafe 描述为定义 compiler 无法验证的额外 safety condition,或由作者声明这些条件已得到满足的位置。unsafe block 允许 raw pointer 解引用、调用 unsafe function 等特定 operation,但正如 Rust Book 明确说明的那样,它不会关闭 borrow checker 或其他常规安全检查。Rust Reference 对 undefined behavior 的规则在 unsafe 代码中也仍然适用。63

因此,与其把 unsafe 看成“脱离 Rust 规则的自由区”,不如把它看成proof obligation 改变位置的边界。Rust Reference 使用的 proof obligation 并不意味着要求像 SPARK 那样的 machine-checked formal proof。

Reference 说明 obligation 可以通过 run-time check、data-structure invariant 等多种方式 discharge。本节用这个词表示:对 compiler 无法验证的 safety condition 进行有依据的确认并持续维护的责任。如果 unsafe implementation 维持必要 invariant,并构造出 safe client 无法触发 UB 的 API,那么该 abstraction 可以提供 safe interface。

反之,如果只调用 safe API 的 client 仍能到达 UB,那么就像第 3.2 与 3.6 节所述,abstraction 的 soundness 已经破坏。责任并不是从 compiler 整体转移给 developer,而是分布在 compiler check、unsafe contract、library soundness 与 application invariant 之间。63

C++ 也不是只靠“开发者选择”运行

如果只用“可选 pattern 对强制 compiler rule”来描述 C++ 与 Rust 的差异,同样过于宽泛。C++ 的 object lifetime 与 destructor semantics 是语言规则;一旦选择 std::unique_ptr,copy 限制与 ownership-transfer interface 等约束就会由 type system 与 compiler 实际执行。C++ Core Guidelines 也建议用 unique_ptrshared_ptr 表达 ownership,并明确指出 unique_ptr parameter 不只是记录 ownership transfer,也会 enforce 它。65

同时,C++ 可以使用 raw pointer、显式 new/delete 和 custom lifetime protocol;Core Guidelines 的部分规则也依赖 guideline checker 或 static-analysis tooling,而不是 compiler 本身。因此,应比较的不是“C++ 没有强制而 Rust 有”,而是ownership 与 aliasing 约束默认覆盖的范围、opt-in type 的角色、escape hatch 的宽度,以及由什么工具在什么时间发现违规。Rust 的 Safe Rust boundary 把 move 与 reference borrowing rule 广泛应用于普通语言使用;C++ 的 RAII 与 ownership-aware type 同样是强语言/库机制,但与更宽的 raw/custom boundary 共存。65

静态检查的保守性与 safe abstraction 的作用

静态检查很强,并不等于 compiler 会直接接受所有 memory-safe implementation。Rust Reference 把 type system 描述为 dynamic safety requirement 的保守近似。在 Rust 官方文档的 split_at_mut 例子中,人可以确认两个 slice 不重叠这一 invariant,但 borrow checker 无法从简单的两次 mutable borrow 形式中直接识别这种 disjointness。标准做法是在小范围 unsafe implementation 中用 raw pointer 和长度条件建立 invariant,再在其上提供 safe API。64

因此,compile rejection 本身并不能证明“预期 operation 实际上 unsafe”。反过来,也不能只因为人认为代码安全,就断言 compiler rejection 是错的。工程上重要的是区分:compiler 可以直接证明的表达、可以转移到 run-time check 的条件,以及必须在 unsafe abstraction 中明确论证的 invariant。这种区分在复杂 graph、intrusive structure、FFI、device memory 等 lifetime 与 aliasing 关系复杂的领域尤其重要。

unwrap() 不是对 ownership 保证进行心理推断的证据

旧文本曾推断,对 compiler 安全保证的信任可能减少防御式编程并增加 unwrap() 使用,但本节没有证据支持这种 developer behavior 的因果关系,因此删除这一主张。关于 Result::unwrap(),标准库文档直接说明的内容更窄:值为 Err 时它会 panic,并且通常建议使用 ? 或显式 error handling 等替代方案。64

是否使用 unwrap() 是与 memory-safety guarantee 分开的error-handling 与 failure-policy 选择。有些代码可能依据 invariant 判断 Err 不应发生;如果假设错误,就可能 panic。该 panic 是 unwind 还是 abort、服务是否隔离或重启、故障如何影响 availability,都是第 3.2 节已经区分的独立问题。ownership 或 borrow checker 不会替应用决定这些运行策略。

与其说责任“转移”,不如把它分层

按照上述区分,“Rust 把安全责任从 developer 转移给 compiler”也过于宽泛。compiler 与 type system 会自动检查指定的 move、borrow、reference rule。unsafe code 作者必须满足 compiler 无法验证的 safety condition,library 作者必须保持 safe API 的 soundness。application 仍要处理 domain invariant、Result 与 panic policy、resource exhaustion、timeout 与 recovery;部署和运维阶段还要承担 dependency、FFI、observability、failure containment、rollback 等独立责任。

在大规模、长期运行和极端环境中,不能把这些层合并成“能编译就安全”。至少需要结合实际 workload 评估 unsafe/FFI surface、dependency 与 compiler/library soundness assumption、run-time borrow check 和 reference counting 等运行成本、panic 与 recovery policy、resource ceiling、tail latency、build/verification cost。这是把第 3.7 节的多轴评价标准应用到 ownership enforcement。

中间结论

Rust 的工程特征可以比“compiler 强制了既有思想”这句话描述得更精确。在 Safe Rust 中,ownership、move 与 borrowing 的重要约束广泛绑定到普通语言使用和 type checking;部分条件会在 RefCell 等 safe abstraction 中转移到 run-time check;而 compiler 无法直接验证的低层 invariant,则以明确的 unsafe proof obligation 与 sound abstraction 形成边界。C++ 也通过 RAII 与 ownership-aware type 拥有由 compiler 实际执行的规则,但 raw/custom lifetime boundary 与 guideline/tool enforcement 的范围不同。

因此,比较核心不是“developer 还是 compiler”,也不是“可选还是强制”,而是什么 property 在哪里、在什么条件下被 enforce,以及边界之外的 proof、logic、failure、resource、operation 责任留在哪里。这样既可以承认 Rust 在 memory safety 上的优势,又不会把 compiler enforcement 扩大成对 functional correctness、panic recovery、availability 或整个系统安全性的保证。第 4.3 节将把这种保证机制的比较扩展到 Ada/SPARK 的 contract 与 proof 视角。

4.3 Rust、Ada 与 SPARK:所有权、访问、契约和证明的边界

正如第 4.2 节所示,保证机制不能被简单分成“编译器自动阻止”和“开发者编写契约”两个格子。本节沿着共同的比较轴分析 Rust 的 ownership/borrowing、Ada 的 access type 与 language-defined run-time check,以及 SPARK 的 Memory Ownership Policy 与 contract/proof:可表达的数据结构、aliasing 与 mutation 约束、检查位置、proof scope、escape boundary 和执行成本。按照第 4.2 节已经限定的含义,Rust 的 unsafe proof obligation 并不等同于 machine-checked formal proof;SPARK 的 proof 同样只能在分析范围、契约与假设闭合的条件下解释。

双向链表是揭示这些差异的好案例,但首先必须缩小比较单元。像标准容器那样不向外暴露 node 的封装双向链表、多个对象长期保存 node handle 的共享图结构,以及 node 本身嵌入其他对象的 intrusive structure 是不同问题。把一个代码示例当作所有情况的代表,会混淆语言表达力、库设计、安全边界和性能成本。

Rust:不是禁止循环结构,而是区分安全表示与所有关系

Rust 标准库提供具有安全 public API 的双向链表 std::collections::LinkedList<T>。官方文档把它描述为拥有 owned node 的 doubly-linked list,并明确指出,在大多数普通 workload 中,VecVecDeque 通常更快、更节省内存,也能更好地利用 CPU cache。66 因此,“Rust 无法安全实现双向链表,所以必须使用 Rc<RefCell<...>>”并不成立。

当数据结构直接暴露 node identity 和外部共享 handle 时,问题才发生变化。Rc<T> 提供 single-threaded shared ownership,RefCell<T> 可以把 borrowing 检查移到 run time,back-reference 也可以使用 Weak<T> 来避免 strong reference-count cycle。但这只是一种可行的 library-level 表示,并不是 Rust 双向链表的唯一答案。还可以采用 arena/index handle、generational handle、封装的 container API,或者在很小的 unsafe implementation 中维护所需 invariant。

也不能说 Rust 在语言层面禁止 reference cycle。Rust Book 明确展示了使用 Rc<T>RefCell<T> 可以形成 strong-reference cycle,从而使 value 无法 drop 并造成 memory leak。Weak<T> 是不表达 ownership 的 reference,可用于打破这类 ownership cycle。66 按照第 3.2 节的区分,这种 leak 是 resource/availability 问题,而不是 memory-safety UB。

Ada:access type 允许循环和共享表示,但这种表达力不是自动的 memory-safety proof

普通 Ada access type 可以直接表达 node 的 PrevNext 指向其他 node 的结构。language-defined check 可以在 null access 解引用、各种 range 或 overflow 条件等情况下于运行时检测错误并抛出异常。但如第 3.4 节所述,unchecked operation、explicit deallocation、外部接口和 lifetime protocol 仍留下独立的 proof 或 review obligation。因此,能够直接表达结构自动证明不存在 dangling access、double deallocation、leak 或 protocol error不是同一个命题。52

Ada contract 也是独立的一层。precondition、postcondition、type invariant 等可以配置为 run-time check,也可以作为 SPARK analysis 的 specification。因此,如果把 “Ada/SPARK” 合并成“通过写契约来换取自由 pointer”的单一模型,就会抹去 Ada 语言和 SPARK subset 之间的差异。

SPARK:比 unrestricted Ada 更严格地限制 pointer aliasing,因此在这一轴上也具有可与 Rust 比较的 ownership discipline

SPARK User’s Guide 明确规定,对 access value 应用 Memory Ownership Policy 来限制 arbitrary aliasing。mutable memory 在同一时刻只能有一个 read-write owner,或者多个名称只能持有 read-only permission。对 access object 赋值时可能发生 ownership move,并移除 source 的 read/write permission;borrowing 与 observing 也由独立规则约束。67

这些限制的目的是让 pointer 指向的 memory 能够被形式化验证。一个重要结果是,对于循环或共享 pointer graph,SPARK 反而比 unrestricted Ada 更严格。当前 SPARK User’s Guide 说明,pointer-based data structure 在不包含 cycle 或 sharing 时可以实现和验证;典型 singly linked list 和 tree 是支持示例,而 doubly linked list 与 DAG 的 conventional pointer 形式并不受支持67

不过,这个限制针对的是在 SPARK ownership model 内直接表达 cyclic/shared pointer graph,并不表示“双向链表”这种抽象数据结构不能在 SPARK 中使用。

SPARK Libraries 提供 SPARK.Containers.Formal.Doubly_Linked_ListsSPARK.Containers.Formal.Unbounded_Doubly_Linked_Lists,官方指南也建议在实际可行时用此类 container abstraction 替代 pointer-intensive structure。

同时,formal container 的 visible specification 和 contract 位于 SPARK 中,而 private part 与 implementation 位于 SPARK 之外。因此 GNATprove 可以证明 client code 按照 contract 正确使用 container,但这种 client proof 本身并不能证明 container implementation 确实满足 specification。68

因此,原来的“Rust 默认 restrictive,Ada/SPARK 默认 permissive”表格不能保留。必须把 unrestricted Ada 的表达力与 SPARK verification subset 分开,并承认 SPARK 自身就以 ownership 与 aliasing 限制作为可验证性的前提。如果需要 doubly linked relation,应区分是继续把 explicit pointer graph 直接作为 verification target,使用 SPARK formal container 或其 wrapper,让 data structure/traversal algorithm 适配 ownership policy,还是把部分 implementation 放到 full Ada boundary 后面。最后一种选择与其说是 SPARK proof 的解决方案,不如说是缩小 GNATprove analysis scope 的边界;每个选择都会改变 proof scope、需要信任的 implementation 以及 run-time/resource cost。68

SPARK proof 与 Rust unsafe obligation 不是同一种“证明”

在 SPARK 中,GNATprove 执行 flow analysis 与 proof;第 3.4 节整理的 Stone/Bronze/Silver/Gold/Platinum 是不同的 verification objective。Silver 的 AoRTE 目标是在分析范围内证明不存在 Ada run-time error,但 Storage_Error 不在其范围内;Gold/Platinum 的 integrity 与 functional property 也只有在相关 contract 足够表达实际要求、未分析代码和 external assumption 得到正当化的范围内才有意义。53

Rust unsafe 的 proof obligation 表示作者必须论证并维护 compiler 无法验证的 safety condition,它也可能通过 run-time check 或 data-structure invariant 来 discharge。相比之下,SPARK proof 包含由 GNATprove 机械地 discharge 明确 verification condition 的过程。两种机制都具有“自动化边界外仍有人需要负责”的工程共性,但证据形式、自动化程度、proof target 和 trusted assumption 并不相同

用相同单位比较双向链表案例

比较轴 Safe Rust / Rust library Ada SPARK
一般双向链表使用 可使用标准 LinkedList<T> 的 safe API 可用 library/container 或 access type 表达 可使用 SPARK Libraries 的 formal doubly-linked-list abstraction;direct cyclic pointer graph 仍受 ownership-policy 约束
direct Prev/Next pointer graph 仅用 safe reference 很难直接表达长期 cyclic mutable graph,需要其他 abstraction 普通 access type 可直接表达 含 cycle/sharing 的 conventional pointer graph 受 Memory Ownership Policy 限制
shared ownership 与 back-reference 可组合 Rc/RefCell/Weak;strong Rc cycle 可造成 leak 在 access/controlled abstraction 等机制间选择 仅在 ownership/borrowing/observing 规则内允许;arbitrary aliasing 受限
mutation 检查 native borrow 在 compile time;RefCell 在 run time 分散在 language check 与 application protocol flow/proof + ownership policy + 必要的 run-time check
低层 escape boundary unsafe invariant 与 safe-abstraction soundness unchecked operation、raw representation、deallocation/FFI boundary SPARK_Mode => Off、external/non-SPARK code、assumption 构成 proof boundary
更广的 correctness proof 一般 functional correctness 需要独立 specification/tool 可表达 contract 并进行 run-time check 可针对明确 contract 与 assumption 分阶段进行 AoRTE、integrity、functional proof;formal-container client proof 不证明 private implementation 本身满足 specification

这个表格不是为了把语言压缩成“更灵活”或“更安全”的单一排名。即使同为 doubly linked list,是否复用标准 container、是否向外暴露 node identity、是否需要 intrusive layout、是否必须控制 allocator、是否存在 worst-case latency 和 memory ceiling,都会改变成本结构。

在大规模和极端环境中,尤其需要用 benchmark 和 resource bound 验证 representation cost。Rust 标准文档直接说明,array-based Vec/VecDeque 通常比 LinkedList 更快、更节省内存,也更能利用 CPU cache。66

SPARK formal container 也不存在单一成本模型:bounded definite formal container 不使用 dynamic allocation,而 unbounded indefinite formal container 会对 element 和内部 storage 扩展使用 dynamic allocation。68

因此,Rc 的 reference counting、RefCell 的 run-time borrow check、Ada 所选择的 access/allocation representation、SPARK 的 container variant 或 pointer representation,以及 proof effort,会分别产生不同的 CPU、memory、latency 与 verification cost。哪种成本占主导,不能脱离 workload、hardware、lifetime pattern、allocator policy 和 proof objective 的测量来判断。

中间结论

双向链表案例并不支持“Rust ownership 阻碍复杂数据结构,而 Ada/SPARK 可以通过 contract 自由解决”的结论。Rust 可以通过 safe API 提供双向链表;直接设计 shared node graph 时则必须显式考虑 ownership、borrowing 以及 runtime/unsafe abstraction 的成本。Ada 更容易直接表达 cyclic pointer structure,但这种表达力本身并不等于 lifetime safety 或 whole-correctness proof。SPARK 作为 Ada subset,对 pointer aliasing 施加 ownership restriction,限制 conventional cyclic pointer graph,同时也提供 formal doubly-linked-list container abstraction。即使如此,client proof 与 library implementation 满足 specification 仍然是不同的 verification boundary。68

因此,比较核心不是谁更受限制,而是面对所需 data structure 与 property 时,选择哪种 representation,language/type/runtime/proof 排除哪些 error,哪些 invariant 与 assumption 仍由人维护,以及这种选择如何影响 performance、resource 与 verification cost。这个视角把第 3.4 节的 Ada/SPARK assurance boundary 与第 4.2 节的 Rust enforcement boundary 放到同一套工程标准下。


第三部分:生态系统现实与结构性成本

第三部分分析 Rust 生态系统面临的实际挑战及其背后的结构性成本。在评价 Rust 的开发者体验、零成本抽象原则和实际工业应用限制时,有必要根据性质把问题分成两类。

  1. 成熟度问题: 库不足、部分工具不稳定、文档不完善等问题,可能随着时间和社区投入的积累而自然解决或缓解。这是所有成长中的技术生态系统都会经历的成熟度问题。

  2. 设计内在的权衡: 为实现语言的核心价值,例如运行时性能和无 GC 的内存安全,而有意牺牲其他价值,例如易学性、编译速度或实现特定模式的灵活性。它们是“选择”而不是“缺陷”,因此很难仅随时间推移而消失。

后续章节将以这一分析框架为基础,明确区分并评价 Rust 各项技术挑战属于哪种问题。

5. 开发者体验的成果与成本

第 5 章要问的并不只是 Rust 是否“难”或是否“有生产力”。更准确的问题是:语言、编译器、库与工具中的哪些机制产生了怎样的开发体验,以及证据能够在多大范围内从个人的学习体验扩展到团队与组织的生产力

这里的开发者体验(DX)不是一个单一数值。学习与心智模型形成、编译器诊断与 edit-build-test 反馈、实现、重构、代码审查与调试、库与依赖发现、build/CI 资源,以及运行维护体验,都是不同的维度。生产力同样不能简化为“编译是否更快”或“代码行数是否更少”;还必须说明在何种工作负载与组织中测量了任务完成时间、返工、缺陷逃逸、review cycle、training/mentoring 成本与长期维护成本。

第 5.1 节以借用检查器以及所有权、生命周期的学习为例,整理这种证据边界。第 5.2 节考察把技术选择推广到其他问题领域的推理;第 5.3~5.4 节讨论 async 与错误处理的具体成本;第 5.5~5.7 节讨论库、工具链与构建环境。各节都会把语言机制的事实与在用户、团队、组织中观察到的结果分开。

5.1 借用检查器、学习曲线与生产力:证据边界

“因为 borrow checker 很难,所以 Rust 的生产力低”这一句话,把四种不同层次的主张合并在了一起。

主张层次 需要确认什么 合适的证据
语言/编译器行为 哪些 move、borrow、引用关系会在编译时被拒绝 Rust Reference、官方 Book、编译器诊断
learnability 哪些概念会被哪些学习者认为困难或被误解 学习实验、用户研究、明确范围的 survey
task-level productivity 特定任务的实现、修改、debugging、review 时间如何变化 可比较的 task、观察研究、实验
team/organization outcome onboarding、进度、维护、缺陷与 incident 成本的净效应是什么 长期 project data、组织级比较、混杂因素分析

第一层可以直接从语言文档确认;后三层需要独立的经验资料。尤其不能仅凭编译器拒绝某段代码这一事实,就推断组织的进度或成本。

技术保证:不要把所有权整体等同于借用检查器

Rust 的所有权规则由编译器检查。在赋值或按值传递函数参数等会转移所有权的语境中,non-Copy 值会 move,而 Copy 值可以 copy。Rust 也会静态限制引用有效性以及 shared/mutable borrow 冲突等条件。不过,正如第 4.2 节所区分的,并非所有与所有权有关的机制都由借用检查器在同一位置、以同一种方式处理。Rc<T> 在库层面提供 shared ownership,RefCell<T> 把部分 borrow 检查移到运行时,而 unsafe 并不是简单关闭普通检查的例外;它会为编译器无法直接验证的 safety condition 产生独立 obligation。69

因此,把教学中的“one owner”扩展成“每个值在任何时候都只有一个 binding”是不准确的。Copy 值可在赋值或函数传递时 copy;borrowing 允许在不转移所有权的情况下访问,并可同时存在多个 shared reference。Rc<T> 等库抽象还可表示通过引用计数实现的 shared ownership 等其他所有权关系。Safe Rust 的引用规则会在 sound 的 Safe Rust 范围内阻止 dangling reference 和被禁止的 mutable aliasing,但不会自动保证包含第 3.2 节所述 unsafe、FFI 与 soundness 边界在内的整个系统的 correctness 或 availability。

生命周期标注也不是在运行时延长对象寿命或赋予对象新寿命的记号。官方 Book 说明,标注描述的是多个引用生命周期之间的关系,很多情况下由于 lifetime elision 与 inference,并不需要直接写出。需要标注的场景可能因陌生而带来学习成本,但更准确的说法是:标注表达关系,使编译器能够验证引用有效性,而不是“写出的 lifetime 本身防止 dangling pointer”。69

编译错误并不立即意味着“算法不安全”或“数据结构无法表示”

静态分析可能限制可接受的表示方式,编译器也可能无法直接检查程序员意图中的 invariant。像第 4.2 节的 split_at_mut 案例,可以在 safe API 内部建立范围狭窄的 unsafe invariant;也可以像第 4.3 节那样选择 container、index/arena、reference counting、run-time checking 等其他 representation。因此,借用检查器拒绝能够直接确认的是:当前程序表示因为不满足 Safe Rust 的静态规则而被拒绝。仅凭这一事实,不能证明问题本身存在 semantic unsafety,也不能证明某种数据结构不可能实现。

这种区分对学习同样重要。初学者遇到的编译错误,既包括确实必须禁止的引用关系,也包括需要采用其他所有权表示的设计,还包括必须在 signature 中写明生命周期关系的情况。编译器诊断在这一过程中既可能成为摩擦成本,也可能成为学习工具。2024 State of Rust Survey 报告,一些回答“learned by doing”的受访者会把 rustc error message 与 Clippy 当作 guide。总结 2025 年 Rust Vision Doc 研究的 2026 年学习后续文章也报告,多位 interviewee 把编译器诊断描述为学习 lifetime 与 borrow 关系的重要资源。70

可以观察到学习困难,但不能把它推广成一条固定的“Rust 学习曲线”

学习成本本身有经验依据。ICSE 2022 的 mixed-methods 研究分析了 100 个 Rust 相关 Stack Overflow 问题,并对 101 名 Rust programmer 进行了 survey,发现理解和应用 ownership/lifetime safety rule 时存在反复出现的困难。OOPSLA 2023 研究评估了一种测量 ownership 概念误解的工具和新的 pedagogy;其 initial deployment 报告,相比 original version,Ownership Inventory score 平均高 9%(N = 342, d = 0.56)。OOPSLA 2024 的后续研究分析了 62,526 名 Book 读者在 13 个月中提交的 1,140,202 条 quiz 回答,观察到 ownership type 等困难概念附近的学习流失,并报告 12 项教育干预使目标题目的得分平均提高 20%。70

这些结果同时说明两点。第一,ownership、borrowing、lifetime 确实可能产生可测量的学习难点。第二,这种难度不是固定的语言常数,而会随着解释方式、diagnostics、练习、prior experience、mentoring 等条件变化。2024 State of Rust Survey 中,Rust 非用户约有 31% 把“感知到的困难”列为不使用 Rust 的主要原因,而 53% 的调查受访者把自己的 Rust expertise 评价为 productive 水平。但 7,310 份完整回答中约 92% 来自 Rust 用户,而且调查主要触达既有 Rust 开发者,因此不能把这些数字推广为整个开发者总体的学习时间或生产力分布。70

Rust Vision Doc process 收集了约 4,200 份 survey 回答和 70 多次 interview。2026 年的学习后续文章给出了 prior experience、组织 training、mentoring、低风险初始 task 等背景影响学习路径的案例。不过,研究者明确指出 selection bias,包括难以充分招募拒绝或停止使用 Rust 的人,也说明研究主要关注 individual developer experience,而不是整个组织。因此,这些定性 pattern 可以展示体验的多样性与可能的支持方式,却不能估计其出现频率、标准 ramp-up 期限,或对组织生产力的因果效应。71

学习成本与净生产力是不同变量

编译时拒绝可能增加实现过程中必须立即处理的工作。相反,在运行前阻止某些错误引用关系,也可能减少后续 debugging 或缺陷修复。哪一种效果更大,取决于 task、codebase、defect mix、编译器反馈质量、团队经验,以及 review、test、CI 过程,因此无法仅从语言机制决定净效应。

Rust Project 自身的 survey 也显示了这一点。2021 survey 中,在工作场所采用 Rust 的受访者有 83% 认为采用过程 challenging,但只有 13% 表示 Rust 让团队变慢,82% 则表示 Rust 帮助团队实现了目标。这是带有 self-report 与 self-selection 的样本,不能证明 Rust 具有生产力优势。

更合适的用途是把它视为一个反例:“采用很困难”的回答与“帮助了团队”的回答可以同时存在,因此不能从学习难度直接推断净生产力

2025 State of Rust Survey 也把 slow compile time、storage usage 与 debugging 等列为不可忽视的 productivity 问题,同时 survey team 明确警告,不要从 7,156 份回答以及人数更少的 optional-question 回答中过度外推到整个总体。71

因此,本书若要声称“生产力”,至少必须明确测量单位。评估初期学习时,可以观察 time-to-first-change、达到能够独立维护的时间、mentoring 时间;评估开发流时,可以观察实现时间、review cycle、rework、defect escape、debugging 时间。在大型仓库和极端环境中,不仅要看平均值,还应分别考察 p50/p95 edit-build-test latency、CI 的 CPU、memory、storage 成本、专家瓶颈与 bus factor,以及长期 refactoring 成本。如果同时观察到安全缺陷减少与开发时间增加,就应把两者都放入成本模型,而不是隐藏其中一项。

话语边界

学习困难不是衡量开发者智力或专业地位的指标;反过来,学习更快或语言更简单也不意味着工程上更低劣。这类身份与能力判断必须与技术保证和生产力测量分离;若要主张频率或因果关系,则需要第 3.6 节规定的 discourse sampling 标准。第 5.1 节不会从网络轶事推广学习者行为或组织文化。

中间结论

现有证据支持这样一个结论:Rust 的 ownership、borrowing、lifetime 可能给部分学习者带来实质性学习成本。同时,也有证据表明 pedagogy 与 diagnostics 可以提高理解度,学习体验会随 prior experience 与组织支持而变化。相反,仅凭借用检查器的存在,就得出项目生产力必然降低或进度可预测性必然恶化的普遍因果结论,超出了现有证据

工程上真正需要比较的,不是“学习曲线是否陡峭”这一单一评分,而是特定组织与工作负载中,学习、实现、build、debugging、review、缺陷、运行、维护成本如何随时间重新分配。坚持这一标准,既可以承认 Rust compile-time 保证的收益,而不把它自动扩大成生产力优势;也可以承认学习成本,而不把它自动扩大成生产力劣势。

5.2 技术选择的普遍化倾向与工程权衡

“Rust 在某个特定问题上有优势”与“因此应当把 Rust 的适用范围进一步扩大”并不是同一个命题。前者是关于语言、compiler、library、toolchain 的特性与特定 workload 之间适配性的主张;后者则是把该结果转移到其他 workload、project、organization 的普遍化主张。本节不预先扩大或缩小任何技术的适用范围,而是考察:当条件性的优势被转化为更广泛的技术选择建议时,还需要哪些额外证据。

技术选择的论证至少可以分为以下四个阶段。

主张阶段 需要确认的内容 适当的证据
技术特性 语言、compiler、runtime、library 提供哪些保证或成本特性 specification、官方文档、可复现 benchmark
workload 适配性 该特性对于当前 system 的 defect model、latency、throughput、memory、real-time、deployment 要求是否重要 需求、production profile、load test、incident 与 defect data
比较适配性 在相同要求下,候选技术的总成本与风险有何不同 相同 workload 的比较、prototype、migration experiment、lifecycle cost 数据
可普遍化性 一个 project 的结果能否转移到其他 domain、组织或时期 多 project、多组织数据、明确 sampling、longitudinal data、confounder 分析

第一阶段的优势再强,也不会使后续阶段自动成立。反过来,某个 project 没有选择 Rust,也不意味着 Rust 不存在技术优势。正如第 3.7 节总结的那样,defect model、保证边界、运行成本、assurance、变更策略、组织与 lifecycle cost 是不同的比较轴。

“工具定律”是方法论警告,而不是 Rust 特有的因果定律

Abraham Kaplan 在 1964 年 The Conduct of Inquiry 中讨论的 “law of the instrument”,以及 Abraham Maslow 在 1966 年 The Psychology of Science 中的 hammer 比喻,可以作为一种方法论警告:熟悉或擅长的方法可能连问题的定义方式也一并收窄。72 但这些著作不是对 Rust developer 的研究,也没有测量“学习某种 programming language 所投入的时间产生 sunk-cost-like 心理,从而扩大其适用范围”这一因果效应。

因此,如果像旧稿那样把“为学习 Rust 投入的努力可能推动更广泛的应用尝试”视为 Rust 采用中已观察到的机制,就需要另外的证据。例如,需要追踪学习前后候选技术与判断标准的 longitudinal data、实际 architecture decision record、可比较的组织样本,以及控制需求和既有 stack 的研究。没有这类资料,就不应仅根据技术选择结果反推 developer 的动机或心理。

而且,熟悉本身并不总是 bias。 Software architecture 中的 technology choice 也会考虑可用 tool、组织内部 familiarity、外部 support、选择造成的 side effect,以及与既有 stack 的 compatibility。73

在 2024 State of Rust Survey 中,工作中使用 Rust 的受访者有 21% 表示,因为自己已经熟悉 Rust,所以把它作为 default choice。74 这说明 familiarity 在该样本中被 self-report 为选择理由;它并不能证明该选择不理性或属于 “golden hammer”。

既有专业能力、运行知识、build infrastructure 与 training 资产会改变真实的 switching cost 和 failure risk,因此仅凭选择结果无法区分认知 bias 与合理的 lifecycle cost。

技术选择不是单一优势的排名,而是对明确要求的比较

这并不是说 memory safety、无 GC、低 latency、快速开发、library ecosystem 或 formal assurance 中的任何一项不重要。在特定环境中,一项要求可能成为 hard constraint,从而大幅缩小候选范围。问题在于,没有说明该条件,就把一个轴上的优势转换成整体技术排名。

在大型或极端环境中比较候选技术时,为了可复现,decision record 至少应留下以下内容。

评估轴 需要确认的问题
workload 与 resource 除 steady-state 外,p50/p95/p99 tail latency、peak throughput、memory headroom、startup、code size、worst-case timing 需要达到什么要求
defect 与 assurance memory error、data race、logic error、resource exhaustion、availability failure 中哪些需要在什么 boundary 内被预防、检测或证明不存在
ecosystem 与 integration 所需 protocol、database、SDK、library、platform、native dependency、observability,以及既有 build/deploy stack 是否真正受到支持
staffing 与 workflow 当前 expertise、hiring、onboarding、mentoring、review、debugging、expert concentration 与 bus factor 的成本是多少
migration 与 operation 能否与既有资产 interoperability,是否支持分阶段迁移、rollback、incident response、data migration 与并行运行
lifecycle 与 toolchain build/CI 的 CPU、memory、storage、dependency update、security response、toolchain support、长期 refactoring 与 rewrite opportunity cost 如何累积

这张表不是报告某种语言平均效果的 empirical result,而是一种避免在比较中遗漏重要条件的 decision procedure。实际权重与通过标准必须由 project 要求决定。

这些标准也不是为了得出某种语言始终优越的结论。例如,如果 memory-safety defect 是主要风险,而 workload 又同时要求 low-level control 和严格的 resource budget,那么给予 Rust 的条件性优势较高权重可能是合理的。相反,如果 application 的 bottleneck 是 database 或外部 service,而组织的主要风险是功能变更速度、与现有 framework 的 integration 和人才供给,那么其他轴的权重可能更大。无论哪种情况,在没有实际要求和测量时,都不应把一个特性扩展成整体判定,例如“有 GC 所以不适合”“没有 static type 所以不稳定”“Rust 很难所以生产力低”。

Web backend 不是“过度应用”的证据,而是必须说明条件的真实使用领域

旧稿把将 Rust 用于某些普通 web backend 的主张直接作为普遍化案例,这一表述范围过宽。2024 State of Rust Survey 报告称,在受访者的 technology domain 中,server backend、web/networking service 与 cloud technology 尤其常见。74 正如第 5.1 节所确认的,该 survey 的 7,310 份完整回答中约 92% 来自 Rust 用户,而且主要面向既有 Rust developer,因此无法据此估计整个 backend 市场的 share 或相对优越性。但这些资料同样不支持这样的前提:backend 这个 domain 本身属于 Rust 的异常使用或天然超出其适用范围。

因此,要考察的不是“是否把 Rust 用于 backend”,而是该主张附带的条件。如果某个 API gateway 或 service 的核心要求确实包括 tail latency、memory footprint、memory-safety 要求和 concurrency defect model,而且 benchmark 与运行数据表明它适合,那么在这些条件下采用 Rust 可以有直接的工程依据。反过来,仅凭 SaaS、内部 system、commerce service 之类的名称,也无法决定 Go、Java、C#、Python 或 Rust 哪一个更合适。必须以同一标准比较 database latency、deployment model、framework dependency、team expertise、security requirement、traffic distribution 与既有资产。

这种对称性也适用于负面的普遍化。“Rust 的 memory safety 与 runtime performance 是优势,因此应当成为所有 backend 的 default”这一主张,需要能把结论扩展到其他 workload 的证据;“Rust 有学习成本,因此不适合普通 web backend”这一主张,也需要同等水平的比较资料。条件性的成功案例或成本案例可以说明可能性与 failure condition,但没有抽样设计,就不能决定整个 domain 的平均效果。

把话语的存在与频率,同技术选择的原因分开

第 3.6 节规定的 sampling 标准同样适用。如果在选取的公开帖子中发现“某技术有一个优势,所以也应当用于其他 domain”这样的论证,它可以说明这种论证形式的存在。但没有预先定义的 corpus 与 sampling,就不能估计这种论证在 Rust community 中是否常见、是否占主导,或者实际改变 adoption decision 的程度。58 反过来,仅凭少数相反方向的轶事就断言 Rust 用户不会普遍化,也是同样的错误。

中间结论

目前核实的资料直接支持三个结论。第一,“工具定律”和 hammer 比喻提供了一种方法论问题,用于检查熟悉的方法是否可能收窄问题定义。第二,technology choice 不应只比较 workload 与 quality attribute,还应同时比较 tooling、expertise、compatibility、migration、operation 与 lifecycle cost。第三,Rust 确实被用于 server backend 与 web/networking 领域,因此 backend 采用本身不能被当作普遍化的证据。

相反,现有证据不足以得出以下因果、频率或平均效果结论:学习 Rust 的 developer 因投入成本而扩大其适用范围Rust community 比其他语言用户更频繁地进行 golden-hammer reasoning,或者 Rust 在普通 web backend 中普遍更加优越或更加低劣。要支持这类结论,需要预先定义的 developer、organization 总体或 discourse corpus,需要记录候选技术与要求条件的 decision data,需要来自相同或可比较 workload 的成本、defect 与运行指标,还需要能够处理 expertise、legacy、deadline、architecture 变化等 confounder 的研究。本节的工程结论更窄:技术优势可以成为采用依据,但适用范围应由明确的要求条件与比较资料决定,而不是由优势的名称决定。

5.3 异步编程模型的复杂性与工程权衡

评估 Rust 的 async/await 时,必须区分语言定义的 Future modelexecutor 与 I/O runtime 的实现library ecosystem 的 API 选择FFI boundary,以及在特定 workload 中观察到的成本。旧稿把这些层次合并成一个“异步模型”,并把概念复杂性、ecosystem fragmentation、interoperability cost 直接写成 Rust 的固定属性。本节的问题更窄:Rust async 被设计用来降低哪些成本,这种选择产生了哪些其他成本和 integration boundary,而当前证据允许我们把这些成本普遍化到什么范围。

async 不是消除 executor 的功能,而是把执行 policy 放在语言之外的 Future model

根据 Rust Reference,调用 async fn 并不会立即执行函数体,而是返回捕获参数的 Future;只有在该 future 被 poll 时,函数体才继续推进。标准 Future trait 的核心 operation 同样是 poll(self: Pin<&mut Self>, cx: &mut Context<'_>)。官方 Async Book 把这种设计描述为 “zero-cost” async,同时明确说明 Rust 不提供 built-in runtime,runtime 由 community crate 提供。75

因此,不能把 “zero-cost” 理解为 executor、scheduler、I/O driver、timer 或 task management 不存在成本。官方文档直接支持的范围,是 async 不强制要求 heap allocation 或 dynamic dispatch,并且可以在少量 OS thread 上运行大量 I/O-bound task 这一设计优势。实际 application 仍可能需要持续 poll future、传递 I/O readiness 和 timer 的执行层;其实现与配置成本必须与语言语法本身分开测量。

Pin 的复杂性确实存在,但必须区分它暴露出来的边界

compiler-generated future 会保存跨越 await 仍然存在的 local state,而这些 state 之间可能形成地址依赖。Pin 是让这种 address-sensitive value 保持有效地址关系的 contract,compiler-generated Future 是其代表性用例。不过,官方 Async Book 说明,在普通 async/await 使用中,compiler 会处理 pinning,因此 developer 往往不需要直接意识到这些细节。76

Pin 直接暴露给用户的边界更加具体。当开发者直接 poll future 或 stream、处理 boxed future 的具体类型、实现 custom Future,或者编写需要 pin projection 的 low-level library 时,可能需要理解 PinUnpin、projection 及其 safety contract。因此,“使用 Rust async 就要求所有 developer 深入理解 self-referential structure 与 Pin”这一普遍化不准确;反过来,“Pin 只是 compiler 内部细节,因此没有成本”也同样不准确。

这种 usability 问题并不只是外部批评。Rust project 在 2025 年推进了让 async Rust 的使用体验更接近 sync Rust、改善 Pin ergonomics 的工作,2026 project goals 中也包含 Continue Experimentation with Pin Ergonomics。2024 State of Rust Survey 的 open answer 摘要同样把 async programming 的困难列为限制 productivity 的问题之一。77 但 survey 的 open answer 不是针对整个总体发生率的 controlled study,也没有测量 Rust 相对于 Go、Java、C# 的学习成本。这些证据支持的是问题确实存在,而且被视为改进对象,并不支持“Rust async 的平均生产力低多少”这样的结论。

runtime 多样性与 ecosystem coupling 是同一设计选择的两个侧面

Rust standard library 提供 Future 这一最小执行 interface,但不会把某个 executor 固定为标准 runtime。这为 single-thread、multi-thread、embedded 等不同执行策略保留了选择空间。与此同时,application 所需的 task spawning、I/O driver、timer、asynchronous I/O type、shutdown 等功能位于 runtime 或 library API 中,因此两个 library 都返回 Future 这一事实,并不能自动保证 end-to-end interoperability。78

但也不能把它直接扩大成“依赖 Tokio 就会失去与其他 runtime 的兼容性”这样的全面命题。当前 Tokio 文档说明 runtime 把 I/O driver、scheduler、timer 组合提供,同时也明确指出 tokio::sync 中多数 synchronization primitive 是 runtime-agnostic 的,而需要 timer 的 timeout 类 operation 等属于例外。因此 coupling 的单位不是“整个 Rust async”,而是dependency 实际使用的 API 与 resource driver。迁移到其他 runtime 或 library 时,应当在 dependency graph 中检查所需 adapter、feature flag、I/O trait 转换、task-local state,以及 timer 与 cancellation semantics。

这种区别对 maintainability 很重要。选择 runtime 的自由允许针对特定环境采用合适的 scheduler 与 resource policy,但长期运行的大型 system 也必须检查 runtime-specific API 在 public interface 中传播到什么程度、是否有理由在一个 process 中放置多个 runtime 以及其成本、blocking operation 是否占用 executor thread,以及 shutdown 和 backpressure 如何跨越 library boundary。“没有标准 runtime”这一事实本身并不是优点或缺点的判决,而是决定这些选择成本由哪里承担的设计条件。

异步 FFI 的问题不是“不可能”,而是 ABI 没有定义执行 protocol

Rust 可以通过 C ABI 交换 foreign function 与值,但 C ABI 并不会把 Rust Future 的 polling protocol 一并标准化。Rust Reference 的 external block 中声明的 foreign function 不能使用 async qualifier,而 Rust 的 async fn 在调用时返回 opaque future。此外,Future::poll 依赖 PinContext 与 wake-up protocol。79 因此,只共享同步函数调用 ABI,并不能让 foreign event loop 自动 drive Rust future。

这也不意味着必须像旧稿所说的那样“只能 block 或手工编写 callback wrapper”。实际边界可以设计为 callback、opaque handle 加 explicit poll function、completion queue、file descriptor/event notification、message passing、独立 Rust runtime thread,或 host-language binding 提供的 bridge 等多种 protocol。真正重要的比较对象不是是否存在 bridge,而是 ownership、wake-up、cancellation、lifetime、error propagation、shutdown 与 thread-safety 的 contract 由哪一侧负责。FFI 成本不是 Rust async 固有的单一数值,而会随 host runtime 与 ABI protocol 的组合而变化。

不要把机器时间与 developer 时间合并成一个“成本转移”叙事

官方 Rust Async Book 说明,对大量 I/O-bound task,async 相比以 OS thread 为中心的模型可以降低 CPU 与 memory overhead;同时也明确指出,async function 的 state machine 与 runtime 的包含可能增大 binary size。2026 Rust Project Goals 进一步包含 Async Future Memory OptimisationAsync statemachine optimisation;前者的问题说明记录了 nested future 的 memory bloat、部分 cloud/network workload 的 stack overflow,以及 embedded、kernel 等 memory budget 严格环境中的担忧。80

这比“async 是无成本的”或“async 通过牺牲 developer 时间来最小化 runtime cost”这样的单一交换公式提供了更具体的图景。runtime CPU、allocation、future size、binary size、compiler optimization、debugging、integration 与 maintenance 是不同的成本轴。一个轴上的降低不会自动证明另一个轴上的增加。2024 survey 的 open answer 提到 async 与 debuggability 问题,说明真实困难确实存在,但并不能量化 error tracing 时间增加多少,也不能证明它比其他语言更难 debugging。

与 Go goroutine 的比较也必须使用相同的 workload 与成本轴

Go specification 把 go statement 定义为:在同一 address space 内,以独立的 concurrent thread of control,也就是 goroutine,启动一次函数调用。相比之下,Rust async call 会创建 inert future,只有 executor 对其 poll 时才继续推进。81 这是实际的设计差异,但应像下表一样,把机制差异性能、生产力结果分开理解。

比较轴 Rust async/await Go goroutine 结论边界
执行单位 调用时创建 Future,被 poll 时推进 go statement 启动 goroutine 执行 语言层面的执行 model 差异
runtime 关系 无 built-in runtime,可选择 executor/runtime 使用包含 goroutine 与 GC 的 Go runtime 哪个成本更低需要 workload 测量
resource 控制 可避免 allocation 与 dispatch,并选择 runtime 配置 runtime 提供 scheduling 与 memory management 必须记录 peak task 数、stack/heap、scheduler、GC 条件
library integration runtime-specific I/O、timer、spawn API 可能形成 integration boundary goroutine 本身是语言功能,但 library、Cgo、external loop 的边界仍然独立存在 不能简化成“集成性高/低”的单一等级
usability PinSend、runtime context 等可能在特定 low-level boundary 暴露 goroutine 创建语法简单,但 race、cancellation、leak、blocking policy 仍需单独设计 相对学习与 debugging 成本需要 user research

因此,旧稿中“CPU-bound 时 Rust async 更有优势,而 I/O-bound 时 Go 更好”的句子也不能在没有证据的情况下普遍化。Rust async 的主要目标本身就包括大规模 I/O concurrency,而 CPU-bound work 反而可能需要独立 thread pool 或 blocking strategy。相反,Go runtime 的 scheduling 与 GC 成本在某个 latency budget 下是否重要,应根据 workload、runtime version、allocation pattern、GOMAXPROCS 与 hardware 条件测量。不能仅凭语言名称决定 bottleneck 在哪里。

在大型、长期运行与极端环境中,应先记录 failure condition,再看平均 throughput

选择 async architecture 时,与单一平均 benchmark 相比,更应测量 task 数增加时的 peak live future memory、allocator pressure、scheduler queue 与 wake-up storm、p95/p99/p999 latency、blocking call 对 executor 的占用、timer 数量、cancellation safety、graceful shutdown 时间、resource leak、binary size、stack headroom、runtime upgrade 与 dependency compatibility。

在 embedded、kernel、long-running service 等 resource ceiling 或 recovery 要求严格的环境中,worst-case 与 degradation behavior 尤其重要。

只有这些资料,才能区分 runtime 选择自由是否是真实收益、integration surface 是否构成维护成本,以及 compiler optimization 问题是否形成 deployment risk。

中间结论

当前 primary 与 official 资料直接支持以下有限结论。Rust async 是把 lazy Future 与外部 executor 结合的 model,可以在少量 OS thread 上处理大量 I/O task,而不把 heap allocation 与 dynamic dispatch 设为必需。

另一方面,因为 standard library 没有固定 runtime,scheduler、I/O、timer、shutdown API 的选择以及 integration boundary 由 application 与 ecosystem 承担。

Pin 是安全处理 compiler-generated future 的重要 low-level contract,但在多数 high-level async/await code 中被隐藏,在 custom future、stream、projection 等边界上才更直接地暴露。

2026 年 Pin ergonomics 与 async future 的 memory/layout 优化仍然是 project goal,这说明该领域的成本与 usability 不是固定不变的属性,而是持续的实现与语言设计课题。

相反,现有证据不足以断言:Rust async 通常比 Go 更难学习或生产力更低以 Tokio 为中心的 ecosystem 本质上无法兼容异步 FFI 在实践中不可行,或者 在 I/O-bound backend 中 developer cost 总是超过 Rust async 的执行效率收益。这类比较需要从相同或可比较的 service 中,同时收集 task 数、latency distribution、CPU、memory、binary size、failure/recovery、implementation effort、defect/incident、staffing 与 maintenance 数据。因此,本节对 RQ2 与 RQ3 的结论更加有限:Rust async 的优势与成本应按执行 model、runtime/library boundary、workload、resource ceiling 与组织运行条件拆分评估,而不是从 “zero-cost” 这一口号直接推断。

5.4 重新考虑显式错误处理模型 Result<T, E> 的实用性

评估 Rust 错误处理时,需要区分以类型表示错误传播语法作为独立失败路径的 panic以及application 的恢复策略。旧稿把 Result<T, E> 描述为在 compile time 强制处理所有错误,这个范围过宽。ResultOk(T)Err(E) 表示成功和失败,并带有 #[must_use],因此直接丢弃返回值默认会产生警告;但这是 lint,并非所有程序中不可避免的 hard compile error。调用者仍可向上传播错误、用 unwrap/expect 将其转为 panic,或显式忽略。82

因此真正的问题不是“Rust 是否完全禁止漏处理错误”,而是把可恢复失败暴露在普通返回类型与控制流中会产生哪些收益与成本,以及 application 如何把这一契约连接到运行策略

不能只用“显式对隐式”一条轴比较 Result 与异常

Result 使用 ? 时,遇到 Err(e) 会从 enclosing function 提前返回;若外层错误类型不同,还可通过 From::from 转换,因此并不限于同一种错误类型。83 异常语言也并非只有一种模型。Java checked exception 必须被处理或写入 throws,否则会产生 compile-time error;同时 Java 也有 unchecked 的 RuntimeExceptionError84 Rust 同样存在 panic!unwrapexpect 与 abort 路径。两者都不能概括成“所有失败都进入类型”或“所有失败都对编译器隐藏”。

实际比较应关注错误契约在 API 中出现的位置、正常/失败控制流如何传播、转换与组合、cleanup、FFI 以及 logging/retry/fallback 策略。Result 让错误成为普通返回类型,异常则可把控制非局部地转移到 handler。可读性和维护性取决于 call depth、错误分类、恢复位置、library boundary 与 team convention,不能由语法本身给生产力或可靠性排位。

以 sum type 表示成功/失败早于 Rust

Haskell 2010 已有 MaybeEither,F# 的 Result<'T,'TError> 也是含 Ok/Error case 的 discriminated union。85 这些资料足以说明类似 algebraic-data-type 表达早于 Rust,但不能单独证明 Rust Result 的直接历史来源,或“Rust 将其普及”这样的影响关系;后者需要 Rust 早期设计记录或设计者资料。

错误转换仍有设计成本

大型 application 会同时处理 filesystem、parser、database、network 等不同 error type,因此仍需设计 public error taxonomy。custom enum、source error 保留、context 与 retryability 分类都可能需要代码。但并非每个 call site 都必须写 map_err(...);存在适当转换时,? 可以调用 From::from83 这并不会消除“哪些 dependency error 进入 public API”“context 是字符串化还是结构化保留”“增加 error variant 如何影响 compatibility”等设计问题。anyhowthiserror 的流行本身不能证明标准能力不实用,也不能证明不用 helper 就更好。

panicResult 是不同 failure policy,而不是互斥体系

Rust 通常支持 unwindabort panic strategy。unwind 会在展开 stack frame 时执行 Drop cleanup,一部分 panic 可在 catch_unwind boundary 被观察;abort 则终止 process。Cargo profile 可以选择策略,并存在 target 限制。86 因而在 Result 上调用 unwrap() 更准确地说是把 value-level 的可恢复失败提升到 panic path,而不只是“绕过 compiler rule”。实际后果取决于 thread/process termination、supervisor、request isolation、shared-state invariant 与 FFI。

Cloudflare 2025 展示的是 failure boundary 设计,而不仅是 unwrap 的存在

Cloudflare 2025年11月18日 postmortem 说明:database access-control 变更使 Bot Management feature 生成 query 返回了超出预期的 metadata row,生成 configuration 超过预分配的 200-feature limit。FL2 Rust module 在此条件上产生 error,处理边界中的 Result::unwrap() 把它转为 panic,并与 5xx 响应相连。87 unwrap 的确是实际 escalation point,但并非单一原因;configuration generation、schema/query assumption、resource limit、validation placement、module isolation 与 kill-switch 都属于防御链。直接可支持的结论是:即使有 typed error,application 仍必须设计 recover/reject/isolate/panic/abort 的边界

对大规模、长期运行或资源受限 system,应比较 recoverable/retryable/fatal 分类、错误进入 public API 的范围、causal context、panic/exception isolation、cleanup/cancellation、FFI、logging cardinality、retry amplification、graceful degradation、restart time,以及 error type 变化后的 downstream rebuild 与 migration cost。关键往往是错误如何变成 resource leak、partial state update、retry storm 或 process loss。

中间结论

Rust Result<T, E> 在普通返回类型中表达可恢复失败,? 支持 early return 与 From 转换。#[must_use] 让忽略结果默认产生警告,但不代表所有错误都是 hard compile error,也不消除 panic path。checked exception 同样能提供 compile-time contract。因此 RQ2/RQ3 应在相同 workload 上比较显式 error type、传播/转换成本、non-local flow、cleanup、API compatibility、observability 与 recovery boundary,而不是宣称 Result 或异常在本质上更优。

5.5 Rust 生态的质量成熟挑战与社区话语分析

crates.io 与 Cargo 为 Rust library 的发布与组合提供共同基础。但 package 数量、download 数量或知名 crate 不能把整个 ecosystem 的“质量成熟度”压成一个分数;少量 abandoned crate、文档缺口或 incident 也不能证明整体未成熟。本节区分单个 dependency 的 production suitability与把结果推广到生态总体所需要的 sampling。

0.x 本身不是 API 不稳定性的测量值

Cargo 把 left-most non-zero component 相同的 version 视为 compatible,因此 0.2.3 通常允许 >=0.2.3, <0.3.0;SemVer guide 把 0.y.zy 的变化视作 major-like、z 的变化视作 minor-like。88 这些是 convention,不是所有 project 必须遵守的 hard guarantee。production dependency 应检查 release history、changelog、MSRV、breaking-change policy、deprecation window、CI target 与真实 upgrade test,而不是只看数字 01.0 也不会自动保证 runtime 或 operational compatibility。

文档与维护应按 crate 观察

cargo doc 与 docs.rs 能生成、托管文档,但不能保证文档质量;少数“必须读源码”的案例同样不能估计 ecosystem 平均值。候选 dependency 应检查 API completeness、example、safety contract、platform limit、upgrade guide、MSRV 与 feature documentation。

crates.io/Cargo 支持多个 owner 与 yanking:yanked release 会从新的 resolution 中排除,但不会删除代码或破坏已有 lockfile。89 RustSec 与 cargo-audit 等工具提供已知 vulnerability 检查。90 这些机制可降低部分 maintenance/supply-chain risk,却不保证某个 crate 永久维护。

当前证据显示 challenge 存在,但不提供生态平均质量分数

2025 State of Rust Survey 有7,156份回答,并明确警告不要过度外推;报告显示对 developer/maintainer support 的关注增加,也呼吁企业支持其依赖的 contributor 与 crate author。91 它没有给出 registry-wide bus-factor 分布。约70次 Vision Doc interview 还报告了 crate discovery/trust 以及某些 domain coverage 尚不成熟的问题。92 这些是特定参与者中的 qualitative challenge,并不是 registry-wide reliability、documentation、abandonment rate 或跨生态 ranking。

因此“数量增长但质量未成熟”的总评过强。更有限的结论是:Rust 提供较大的选择空间和有用 infrastructure,同时 project 仍承担 dependency selection、trust、maintainer sustainability 与 domain coverage 的成本,其大小随 domain 与 dependency graph 变化。

成功、失败案例和 community reply 都需要 sampling discipline

serdetokio 可以说明高质量维护的 crate 是可能的,但不能估计所有 crate 的平均 maturity;abandoned/malicious package 也只说明可能的 failure mode。比较前应定义 sampling frame,例如 registry 全体、download threshold、production 的真实 transitive dependency 或 domain-specific candidate,再统一测量 activity、owner concentration、compatibility、MSRV、documentation、CI/test、advisory response、unsafe boundary、dependency depth、license、platform 与 replacement cost。

同样,“Pull Requests are welcome”在某些语境中可能把责任转给用户,在另一些语境中则是合理的开源协作邀请。按照第3.6节,没有预先定义的 corpus 与 coding rule,就不能由少数 forum post 判断哪种功能更常见、Rust community 是否比其他 community 更常回避批评,或这类回应是否真的减少 contribution/bug report。

在大规模、长期运行 system 中,应把每个 dependency 当作一个小型 supply chain,记录 direct/transitive depth、owner concentration、provenance、lockfile reproducibility、advisory response、emergency patch/fork、feature combination、build-script/proc-macro、native dependency、unsupported platform、compliance、replacement lead time、update frequency、CI rebuild cost,以及 abandonment/transfer/yank 的恢复流程。

中间结论

Rust 拥有 publication、resolution、ownership transfer、yanking、vulnerability advisory 的 infrastructure,同时 survey/interview 显示 maintainer support、crate discovery/trust、部分 domain coverage 仍是关注点。但这些证据不能确定 crates.io 的平均质量,也不能给其他语言生态排成熟度名次。RQ2/RQ3/RQ5 因而要求针对明确的 dependency population 测量 compatibility、maintenance、security、documentation、integration 与 replacement cost,并把话语 pattern 与 ecosystem quality 指标分开

5.6 开发工具链的技术挑战与生产力

Rust toolchain 的评估应把 compiler、build system、language server、debugger 的成本分开。compile latency 与 memory/disk 是可测 tool cost;IDE diagnostic latency 与 debugger coverage 是另一类 workflow cost,它们受 codebase、CI、cache、linker、dependency graph 与 debug workflow 影响。

5.6.1 编译器资源使用及其影响

2025 Rust Compiler Performance Survey 收到3,700多份回答,build-performance 满意度平均为6/10,最常见评分为7。报告明确指出 experience 差异很大,不能简单概括成“Rust builds are slow”;同时,不再使用 Rust 的受访者中约45%把较长 compile time 列为至少一个原因。93 对每位受访者自行挑选的“build time 最困扰的 project”,55%在 code change 后 rebuild 需要超过10秒,而且 project size 影响明显。这个问题刻意选择 troublesome workload,因此不是所有 Rust project 的 rebuild distribution,但它能证明某些 codebase 存在真实 incremental-feedback 约束。

monomorphization 是机制之一而不是完整原因。rustc guide 明确指出 concrete generic instance 会带来 compile-time 与 binary-size 成本。94

实际 build 还包含 parsing、macro、type/borrow checking、codegen、linking、proc macro/build script、dependency rebuild、debuginfo 与 cache。survey 还分别讨论 incremental compilation、cargo check/cargo build cache、linking、workspace rebuild、CI caching。

dev profile 的 full debuginfo 有利于 debugging,却增加 build/link time 和 target storage;survey 引用的 benchmark 在一些条件下把它降为 line-tables-only 可改善2–30% cycle count,这本身也是 workflow trade-off。Cranelift、parallel frontend、faster linker 与 workspace rebuild 改进仍在推进。

应测量 p50/p95 incremental rebuild、type-check/link latency、peak RSS、target growth、CI cold/warm cache、parallel memory pressure 与 developer idle time。

5.6.2 IDE 集成与调试环境:抽象背后的成本

同一 survey 中,约87%把 editor inline annotation 作为主要 compiler-error 查看方式;其中约33%认为等待 annotation 是重大 blocker,open answer 经常提到 rust-analyzer performance/memory,超过35%认为 IDE 与 Cargo 的 resource contention 是重大问题。93 这些是 self-selected survey 结果,不是全体开发者平均值。

旧稿说 debugger 总是把 Vec<String> 只显示为 raw field,这也过于绝对。Rust 有 debugger visualizer,其质量随 tool、OS、version 变化。2026 compiler-team debugging survey 说明当前 debugging 是可能的,但某些场景仍不足,并把跨 debugger/OS 支持、type visualizer、first-class async debugging、Rust expression evaluation 列为改进方向。95 因而应实际测量 optimized/generic code stepping、visualizer coverage、async causality、backtrace/core dump/sanitizer/profiler、remote/cross target、incident artifact、symbol、reproducible build 与 postmortem time。

5.6.3 Cargo 构建系统的灵活性

Cargo 统一 dependency resolution、metadata、profile、workspace、feature 与 build command。旧稿把非标准 build 描述成常常超出 build.rs 能力,这个判断过宽。官方文档把 bundled C library、native library 查找、Rust module generation、platform-specific configuration 都列为典型 build-script use case。96

复杂 build graph 仍有成本。build script 需要 compile/run,change detection 不精确会导致不必要重跑;feature 要理解 unification/resolver rule;workspace 共享 Cargo.lock 与 output state,但 package selection、feature combination、cross target 与 native dependency 也会扩大 rebuild surface。97 因此 trade-off 不是简单的“convention over configuration 导致僵硬”。共同 model 能改善 reproducibility/tool integration,而 generated code、non-Rust toolchain、multiple target、hermetic build、受约束 feature set、monorepo cache policy 需要明确 integration layer。应测量 graph invalidation、feature-state 数、native-build reproducibility、cross-compile parity、cache hit ratio、build-script time 与 external-build integration。

中间结论

官方资料支持某些 Rust workflow 中确实存在 compile、editor、disk、debugging 成本,也显示 experience 分散且 bottleneck 不止一个。RQ2/RQ3 应在同一 project/workflow 上比较feedback latency、peak resource、CI cost、diagnostic quality、debugger capability、reproducibility 与 integration maintenance,而不是把一切归因于 monomorphization 或 language complexity。

5.7 开发环境比较:成熟度与设计哲学的交叉点

“Java/C# 是 integrated IDE,Rust 是 VS Code 加分离 toolchain”的比较混合了不同 configuration。editor 可配 language server,IDE 可整合 build/debug/profiling,command-line tool 可负责 automation。真正要比较的是同一开发 task 能否以相近准确性、延迟、资源和自动化成本完成

成熟度不是单一维度

tooling maturity 包括 feature coverage、correctness、latency、resource use、platform coverage、compatibility、documentation、support lifecycle 与 recovery,不能只由历史长短或 language complexity 决定。Rust 当前资料中,2025 survey 同时存在满意和不满意的 build/editor experience,并指出 rust-analyzer/resource contention;2026 debugging status 则指出 tool/OS 差异和 visualizer、async debugging、expression evaluation gap。98 这说明具体 capability gap,而不是给 Rust tooling 一个统一的“早期阶段”评分。

比较同一 task 与 project

symbol rename 可检查 macro/generated/config reference 与 compile/test success;completion 可测 p50/p95 latency 与 memory;diagnostic 可测与 compiler 的不一致;debugging 可测 breakpoint/watch/expression/async causality/core dump;build 可测 cross target/native/generated/cache。”integrated IDE 对 LSP”本身不是 quality score。integration 可能改善 installation/discoverability,却增加 update coupling/footprint;modular tooling 可能便于替换与 automation,却增加 compatibility/setup surface。

在组织规模,应把个人 IDE 满意度与在多 target、多个 OS/architecture、air-gapped build、hermetic CI、长期 branch 上运营 toolchain 的成本分开。记录 installation/index size、update、extension trust、compiler-debugger compatibility、CI image、pinning、offline mirror、support escalation、onboarding、rollback、symbol/source retention,以及旧 release branch 是否仍可 build/debug。

第5章结论

第5章没有把 developer experience 压缩成单一 productivity score,而是分成 learning、technology choice、async、error handling、dependency ecosystem、compiler/IDE/debugger/build workflow。证据支持 Rust 存在真实 learning/workflow challenge,同时也显示其幅度随 population、task、codebase、tool version、organization 变化,并且一部分是可变化的 implementation/ecosystem state。

因此 RQ2/RQ3 要求既不把 compile-time guarantee/runtime performance 自动换算成 productivity,也不把 learning curve/tooling friction 自动换算成 technical unsuitability。可比 project 应一起测量 onboarding、edit-build-test latency、review/debugging、defect escape、dependency maintenance、CI resource、incident recovery、long-term refactoring。RQ5 则把少数 forum rhetoric 与 population behavior/outcome 分开。大规模、长期、极端环境还应加入 p95/p99 feedback latency、peak build memory/disk、expert concentration、toolchain outage/rollback、security response、reproducible debugging artifact 与 multi-year support cost。

6. “零成本抽象”的实际成本分析

评估“Zero-Cost Abstraction(ZCA)”时,首先必须限定所谓“没有成本”具体指哪一种成本。Rust 官方 Book 以 iterator 为例,把 zero-cost abstraction 描述为:使用 high-level abstraction 时,经过优化后相对于可比的 lower-level code 不增加额外 runtime overhead,并把这一思路与 C++ 的 zero-overhead principle 联系起来。99

这并不表示整个 program 的 CPU/memory cost 为零,也不保证每一种 abstraction 都总能生成最优 assembly。官方 iterator 示例本身也提醒,若要做更全面的 benchmark,还需要更多样的 input 与 query。因此第6章的问题更窄:当 Rust 试图降低 runtime abstraction overhead 时,compile、code size、dispatch、linking 与 deployment 会产生哪些条件性成本,其中哪些来自 language mechanism,哪些取决于 build configuration 与 workload?

6.1 成本转移机制:单态化的作用

Rust generic 在许多情况下通过 monomorphization,为 concrete type 生成对应的 machine-code instance。rustc development guide 明确说明,这种方式能生成快速执行的代码,但生成多个 copy 会消耗 compile time,这些 copy 也可能占用 binary space。94 因而在 generic-heavy code 中,monomorphization 确实可能成为 build cost 与 code-size growth 的来源。

但不能据此推出“所有 ZCA 节省的 runtime cost 都会转移为 compile time 与 binary size”这样的普遍规律。并非所有 zero-cost abstraction 都依靠 monomorphization;zero-sized typestate 或被 optimizer 消除的 abstraction 属于不同 mechanism。compile time 与 binary size 还受 macro、type checking、MIR optimization、codegen、linking、debuginfo、dependency、profile 与 target 等因素影响。第5.6节的 compiler-performance 资料同样把实际 build bottleneck 分成多个部分。

monomorphization 会产生机械成本,但最终大小还取决于优化与 reuse

Vec<i32>Vec<String> 等不同 concrete type 上使用 generic function 时,可能需要不同 mono item。但不能假定所有生成的 instance 都会以相同比例留在最终 artifact。inlining、dead-code elimination、linker section garbage collection、可用时的 identical-code folding、cross-crate codegen、LTO 以及真正 reachable 的 call path 都会改变结果。因此不能把 source-level instantiation 数直接换算为 binary byte 数。

dyn Trait 的 dynamic dispatch 在某些设计中可以减少 code duplication,但“改用 dynamic dispatch 就一定减少 compile time 与 binary size”也过于绝对。它会引入 indirect call,并改变 optimization opportunity、object-safety/API shape、allocation 或 pointer representation、branch prediction 与 code locality;compiler 也可能再次优化一部分 dispatch。static/dynamic dispatch 应同时比较 runtime latency、instruction-cache footprint、compile time、size 与 API flexibility。

把 cost shifting 当成测量假设,而不是会计恒等式

如果一个 project 引入 iterator/generic abstraction 后,观测到 runtime work 相同或下降,同时 build time 或 artifact size 上升,那么在该 workload 中确实观测到了 trade-off。但一个轴的改善不会自动证明另一个轴恶化的原因。应尽量固定 baseline、feature set、compiler version、optimization profile、codegen unit、LTO、linker 与 target,再比较前后差异。

对大型 codebase,incremental fan-out 可能比 clean build 平均值更重要。应记录 generic API 改动后多少 crate 被重新 compile、monomorphized code 如何分布到 codegen unit、peak linker memory 与 target cache 如何增长,以及 CI cold build 与 developer warm build 的差异。embedded/kernel 环境还应分别测量 flash/RAM、build-host memory 与 worst-case build time。

中间结论

primary documentation 直接支持的结论是:monomorphization 是 Rust generic 的重要实现 mechanism,并且可能增加 compile time 与 binary space。同时,zero-cost abstraction 是避免额外 runtime overhead 的设计目标,不是整个 lifecycle 无成本的 guarantee。RQ2/RQ3 因而不应假设“成本必然从 runtime 转移到 compile”,而应测量特定 abstraction mechanism 在明确 workload 下如何改变 runtime、compile、code size、dispatch 与 maintenance cost

6.2 二进制大小:设计原则对适用领域的影响

如果不控制比较条件,就不能把“Rust binary 比 C/C++ binary 大”当作语言的固定属性。executable size 同时取决于 linked library、static/dynamic policy、feature set、panic strategy、debuginfo 与 stripping、optimization/LTO、target runtime、libc、linker 与 package format。因此不能把不同 program 的 size 差直接还原为 language-level effect。不过,同一 distribution 与 architecture 的最新 stable repository 中实际 deployment artifact 的大小仍是可复现的运维资料。

2026 年 8 月 28 日,本书从当时官方最新 stable release Alpine Linux 3.24.1 的 v3.24 stable x86_64 repository 下载 busybox、GNU coreutils 与 Rust uutils APK,并直接测量各 package 的主要 multicall ELF。100 三个文件均为 stripped、dynamically linked x86-64 PIE。

表 6.1:Alpine Linux 3.24 stable x86_64 的 multicall executable snapshot

实现 语言 package version 测量文件 file size
BusyBox C 1.37.0-r31 /bin/busybox 804,616 B
GNU coreutils C 9.11-r0 /bin/coreutils 1,138,944 B
uutils Rust 0.9.0-r0 /bin/uutils 9,171,040 B

这是 deployment snapshot,而不是语言间的 controlled experiment。三种实现的 command coverage、dependency graph 与 shared-library closure 并不完全相同,表中的 file size 也不包含 shared library 本身。在这些条件下可以复现 uutils executable 更大的观察,但不能把全部差异归因于 Rust、monomorphization 或 static linking 中的某一个因素。这个 snapshot 更重要的作用,是说明 binary-size claim 必须同时记录 version、architecture、linkage、stripping、feature set 与 dependency closure。

Rust 默认偏好 static dependency,但也支持 dynamic linking

rustc 文档说明,dependency 默认优先 statically link;若两种形式可用,-C prefer-dynamic 可以改为优先 dynamic linkage。Rust Reference 还定义 rlib、Rust dylib、system staticlib 与面向 FFI 的 cdylib101 因此“Rust 因 ABI 不稳定而不能使用 dynamic linking”是不准确的。

另一个独立问题是:能否把 Rust-native ABI 当成长期、独立部署的 plugin contract。Reference 明确指出 extern "Rust" ABI 没有 stability guarantee,default repr(Rust) layout 也只有有限保证,并可能在 compilation 之间变化。另一方面 Rust 提供 extern "C"#[repr(C)] 等显式 interoperability boundary。102 工程问题因此不是 dynamic linking 能/不能,而是哪一种 ABI 与 representation 能在怎样的 version boundary 上承担 compatibility contract

binary size 是 build profile 与 dependency graph 的结果

Cargo 默认 release profile 仍是 strip = "none"lto = falsepanic = 'unwind',所以 release build 并不等于 minimum-size build。Cargo 提供 opt-level = "s"/"z"、strip、LTO、codegen-units、panic strategy 等控制项。官方文档说明,更强 optimization 可能增加 compile time;s/z 并不保证对所有 program 都生成更小 binary;LTO 则在 whole-program optimization 与更长 link time 之间形成 trade-off。103

在不需要 unwinding machinery 的条件下,panic = 'abort' 可能减小 size,但效果取决于 target/program,而且它会改变第5.4节所讨论的 failure policy:放弃 unwind cleanup 与 catch_unwind boundary。stripping 可以缩小 shipped artifact,但 production postmortem 可能要求另外保留 debug symbol。

no_std 不意味着必须手工重写 collection

#![no_std] 会停止自动链接 std 并使用 core。heap-backed type 不在 core 中,但只要环境能提供 allocator,就可以显式链接 alloc crate,并使用 VecBoxString104 因此旧稿所说“no_std 时必须自己实现这些类型”是不正确的。

真正转移的是责任边界:no_std binary 可能需要 target-specific startup/entry 与 panic handling;若要 heap allocation,则要提供 allocator;filesystem、thread、network 等 platform integration 也不会由 core/alloc 自动提供。在 firmware、kernel、bootloader 中,这种显式边界可能是优势;对 application server 则可能是没有必要的成本。

测量整体 deployment footprint,而不仅是 shipped file size

对小 flash target,应分别看 .text/.rodata/.data、relocation、unwind table、allocator metadata、stack/heap budget。container/serverless 可能更关心 compressed image size、cold-start I/O、page cache、shared dynamic page、update transfer 与 symbol sidecar。desktop 上,几 MiB 的 executable 差异可能不如 shared-library compatibility、installer size 与 security-patch propagation 重要。

大型 fleet 还应计算多个 binary 内重复的 static copy、dynamic dependency 带来的 page sharing 与 compatibility risk、vulnerability fix 时的 full-artifact redeploy、debug-symbol retention 与 rollback image storage。binary size 只是 lifecycle footprint 的一个组成部分。

第6章结论

现有证据支持:Rust 试图消除某些 high-level construct 带来的额外 runtime overhead,而 generic monomorphization 在某些条件下可能增加 compile time 与 code size。它还表明 rustc 默认偏好 static dependency,但支持 dynamic linking;Rust-native ABI stability 与 C ABI/representation boundary 是不同问题;Cargo profile 与 no_std/alloc 选择能显著改变 artifact footprint。

但这些资料不能证明Rust abstraction 的 runtime gain 总会一比一转移成 build time 或 binary sizeRust binary 本质上总比 C/C++ binary 大dynamic linking 不可用,或为了小 binary 必须放弃 Rust safety feature。这类结论需要控制 functionality、target、dependency、linkage、optimization、symbol 与 panic policy 的 reproducible comparison。

因此第6章对 RQ2/RQ3 的结论是:不要依赖“zero-cost”名称或 package-size anecdote,而应在一个明确 configuration 中一起测量 runtime latency/throughput、compile time、peak build memory、code/deployment size、link/ABI strategy、failure policy 与 maintenance cost。对大规模、长期、极端环境,还应加入 flash/RAM headroom、cold start、shared-page effect、update bandwidth、patch/rebuild time、rollback storage 与 postmortem symbol retention。

7. 工业应用的约束条件

第 7 章不把 Rust 的工业采用压缩为单一“成熟度”或 adoption percentage,而是分析每项证据究竟证明什么(RQ3),以及何种变更策略在何种条件下合适(RQ4)。语言保证、production deployment、tool qualification、ecosystem 与 staffing、legacy asset、interoperability 和 migration risk 属于不同层次,必须分开考察。

本章依次检查 embedded/kernel 环境的当前支持与 source snapshot(7.1)、safety-critical qualification/certification boundary(7.2)、一般组织的 staffing、dependency、legacy 与 migration 策略(7.3),以及 Google、Microsoft、AWS 的 production adoption case 所能支持的范围与限制(7.4)。每个案例区分 feasibility、observed outcome、prevalence 与 causation,并在章末综合 maintenance、selective replacement 与 full rewrite 等条件性选择。

7.1 嵌入式与内核环境:应用现实与工程挑战

Rust 被作为 C/C++ 替代方案评估的领域之一,是嵌入式系统和操作系统内核开发。但关键边界并不只是能否使用 std。如 6.2 节所述,#![no_std]core 为中心显式暴露执行环境的责任;如果环境提供 allocator,仍可通过 alloc 使用 VecBoxString 等 heap-backed type。相反,thread、filesystem、network、process 等用户态 OS 通过 std 提供的 API 在 kernel 或 firmware 中并不会原样存在,因此 allocator、synchronization、I/O、panic、startup 与 device abstraction 必须适配具体平台。

Linux kernel 的 Rust support 通过 kernel 专用 API 和 abstraction 处理这种差异。当前 kernel documentation 通过 CONFIG_RUST 启用 Rust support,并把 rust/ 下的 support code 与 samples/rust/ 作为开发入口;同时将完整 LLVM toolchain 描述为目前支持最好的 build setup,而将部分 configuration 下的 GCC-based Rust build 标为 very experimental。105 因此不能假定 kernel Rust 拥有与普通 std application 相同的 library surface 来评价其成本与收益。

Rust for Linux 的一个重要设计方向,是在 C 实现的 kernel API 之上构建 Rust-facing abstraction,并由 unsafe implementation boundary 负责向 Safe Rust caller 承诺的 invariant。这不是消除 unsafe,而是把 proof obligation 集中到更小的边界。lock、reference counting、device registration、memory allocation 等 kernel resource 与 application 中同名 type 的约束不同,因此 wrapper 的 lifetime、aliasing、concurrency contract 必须与真实 kernel invariant 一致。

最新 stable Linux 7.2.1 source tree 中 Rust 的范围已经超出早期仅有 infrastructure 的阶段。drivers/android/binder/ 包含 Rust Binder 实现,drivers/gpu/drm/nova/drivers/gpu/drm/tyr/ 也包含 Rust driver code。但 source 自身的 Kconfig 将 Nova 与 Tyr 标记为 work in progress,并说明可能尚不能正常工作。因此,“kernel 中存在 Rust code”与“对应 subsystem 已在 production 中替代 C 实现”必须区分。105

本书重新以最新 stable snapshot 测量 Linux kernel 的 Rust 集成情况。2026 年 8 月 30 日,下载 kernel.org 标记为 stable 的 Linux 7.2.1(2026-08-27)官方 tarball,并使用 cloc v2.04 在 source root 执行 cloc .106 排除注释与空行后,总 SLOC 为 30,518,591 行,其中 cloc 分类为 Rust 的 code 为 114,481 行,约占 0.375%

这里的 0.375% 是 Linux 7.2.1 tarball 全部 source SLOC 中被分类为 Rust 的比例。Rust code 中约 92,808 行位于 rust/,19,726 行位于 drivers/,其余分布在 samples/scripts/lib/mm/tools/。因此不能把它解释为 Rust driver 占比或实际执行的 kernel code 占比。SLOC 也不会按代码重要性、执行频率、安全性效果或维护成本加权。

本书此前的 Linux 6.15.5 snapshot 为 14,194 行 Rust、约 0.05%,因此最新 snapshot 的量化 footprint 确实更大。此前与本次测量都使用 cloc v2.04,因此比较中不存在 tool-version 漂移。即便如此,source tree 本身变化很大,而且 SLOC 不衡量代码重要性或执行占比,因此不把两个 snapshot 的比值当作精确的 Rust adoption 增长率。讨论当前技术状态时采用最新 stable 的 0.375%;8.4 节则以更不容易过时的 低于 1% 这一类别表达来引用该测量。

表 7.1:Linux 7.2.1 source tree 的 cloc 语言分布(SLOC, %)

排名 语言 code lines 占比 (%)
1 C 19,623,126 64.30
2 C/C++ Header 8,400,038 27.52
3 JSON 553,644 1.81
4 reStructuredText 540,837 1.77
5 YAML 518,483 1.70
6 Assembly 230,041 0.75
7 Bourne Shell 159,494 0.52
8 Rust 114,481 0.38

占比以总计 30,518,591 SLOC 为基准四舍五入,仅列出前八个 cloc language category。

与表 7.1 的量化 snapshot 分开看,kernel Rust 的核心工程问题是:safe abstraction 建立在哪些 unsafe proof obligation 之上。CVE-2025-68260 给出了这一边界的具体 failure:Rust Binder 的 death_list 处理将 unsafe list removal 与不相容的并发访问条件结合,导致 data race 与 pointer corruption。107 这并不意味着 Rust 允许 data race,而是说明如果 unsafe implementation 错误地建立了向 Safe Rust 提供的 invariant,边界之外的 guarantee 可能不再成立。

CVE record 将 Linux 6.18 列为 affected,并记录 6.18.1 与 6.19 series 已修复,因此不能把这里测量的最新 stable 7.2.1 描述为未修复状态。107 有效的分析单位不是“Rust kernel 不安全”,而是如何 review、regression test 并在 subsystem boundary 隔离 unsafe operation 的 aliasing、locking、lifetime precondition

阶段性结论

最新 stable snapshot 表明 Linux kernel 中 Rust 的 source footprint 相比本书此前测量已经扩大,而且存在 Binder 与 GPU driver 等实际 driver code。同时 Rust 仍低于总 source SLOC 的 1%,这个数字并不能直接测量 adoption 的价值或 safety effect。嵌入式与 kernel 环境中的 Rust 适用性不能只从 no_std 这一标签推断;必须同时评估 target/toolchain support、allocator 与 panic policy、platform API coverage、unsafe boundary 的可审查性、subsystem maturity、binary/RAM budget、debugging、upgrade 与长期维护成本。

7.2 任务关键系统与国际标准缺失

本节所说的“国际标准缺失”,是指 Rust 语言本身不像 C、C++、Ada 那样被制定为 ISO/IEC 等国际标准语言。这并不意味着不存在可用于安全或任务关键开发的 qualified Rust 工具链,也不意味着不存在商业认证支持路径。在航空航天、汽车、工业控制、医疗器械等要求高保证级别的领域,必须把语言规范的标准化编译器和开发工具的 qualification库的 certification以及最终系统或产品的 certification区分为不同层次。

Rust 本身不是国际标准语言,这一点仍是它与 C/C++/Ada 之间的制度性差异。但国际标准本身也会修订,长期可维护性与可认证性并不由语言是否标准化这一项单独决定。实际项目还必须同时核查所用语言规范、具体编译器版本、验证资料、支持目标、库的适用范围,以及供应商的长期支持条件。

Ferrocene 展示了这种区分。Ferrous Systems 与其子公司 Critical Section GmbH 于2021年公开 Ferrocene,目标是在安全关键领域对 Rust 语言与 compiler 进行 qualification;2022年,Ferrous Systems 与 AdaCore 又宣布面向安全与任务关键市场联合开发。2026年7月28日发布的最新 release Ferrocene 26.05.0,其 compiler 经 TÜV SÜD qualification,可支持 ISO 26262 ASIL D、IEC 61508 SIL 3 与 IEC 62304 Class C 的安全相关开发,并包含 upstream Rust 1.93.0 至 1.95.0 的变更。108 因此,不能笼统地说 Rust ecosystem 不存在面向安全标准的商业 compiler 或 qualification path。

但也不能把这种 qualification 扩大解释为对整个 Rust 语言、所有 Rust program 或随 Ferrocene 分发的全部 development tool 的 certification。Ferrocene Safety Manual 通过 Ferrocene Language Specification(FLS)、指定 target environment、usage restriction,以及用户核实 Tool Confidence Level 与使用环境的义务来限定 qualification scope。公开 qualification 文档把 qualified tool 限定为 rustc,并把 cargo、Clippy、rust-analyzer、debugger、rustdoc/rustfmt 与多种 LLVM tool 区分为 unqualified。不过当前公开的 main 文档是 development-branch preview,因此其中下一 rolling version 的版本号不能当作已经发布的 26.05.0 qualification version。108

compiler qualification 与 library certification 同样是不同层次。最新 26.05.0 release 提供 Rust core已认证子集,范围为 ISO 26262 ASIL B 和 IEC 61508 SIL 2,并把 core::fmt 纳入 certification scope;但并非整个 core 都达到与 compiler 相同的 ASIL D/SIL 3 级别。在航空航天领域,Ferrocene 还说明其支持客户面向 DO-178C DAL C 的 certification effort,但不应把这种支持视为与 ISO 26262/IEC 61508 状态等同的、已经完成的 qualification。108

因此,在任务关键领域评价 Rust 时,核心问题不能简化为“Rust 是否是国际标准语言”。还必须同时考察采用哪一套 Rust 规范与工具链、特定版本和目标平台是否处于 qualification 范围、所需库是否处于 certification 范围,以及最终产品的系统级认证和长期维护责任由谁承担。Ferrocene 是“缺少国际标准语言就必然缺少安全认证路径”这一说法的反例,同时也表明工具 qualification 并不会自动替代具体产品的 certification。

7.3 一般工业采用的壁垒与变更策略

评估 Rust 在一般工业中的采用时,需要区分“语言是否优秀”和“组织今天是否有能力安全地运营它”。人员、dependency、既有系统、FFI、deployment、observability 与 support 属于不同于 language semantics 的约束层,而且各项目取值不同。因此本节不做简单的市场总体排名,而比较组织自身的 capability 与变更策略

人员问题应按组织实际 capability 测量,而不是语言市场排名

2025 State of Rust Survey 报告,计划继续招聘 Rust developer 的组织呈增长趋势。但该调查是以 Rust 为中心的自选择样本,共 7,156 名受访者,报告本身也警告不要过度外推。109 它不能证明“Rust 人才池比 Java/C#/Python 小”“招聘总是更难”或“薪资系统性更高”。

项目应记录实际可用的 Rust expertise、能进行 code review 的人数、unsafe/FFI reviewer 的 bus factor、新成员 ramp-up 时间、incident on-call coverage、培训时间、外部招聘 lead time 与长期 retention。某组织可能最适合培训已有 C++ engineer,另一个组织可能已有足够 Rust 经验。比市场平均口号更直接的约束,是团队能够持续维持的专业能力。

ecosystem 的“成熟度”也必须缩小到 domain 与 dependency

5.5 节讨论的 Rust Project 2026 Vision Doc 资料把 crate 选择/信任以及部分工业 domain coverage 不足记录为真实问题,同时也说明 sample 与一般化限制。92 因而仅凭 ORM、cloud SDK、authentication 等少数例子,把整个 Rust enterprise ecosystem 排在 Java/.NET 之下,超出了证据范围。

实践中应逐项审计所需 protocol、database、cloud、cryptography、GUI、embedded、safety library 的 maintainer capacity、release cadence、security advisory 响应、API stability、platform coverage、license、transitive dependency、offline/vendor 能力、replacement candidate 与 long-term support。缺少所需 crate 或 assurance 不足是真实采用成本,但不能把另一 domain 的成功或失败直接迁移过来。

legacy 是当前状态和未来成本的集合,不是废弃判决

长期运行的系统会在 code 之外积累 test、deployment script、数据格式、operational workaround,以及与客户和设备的兼容性等隐含 specification。software 本身不会物理磨损,但 environment 与 requirement 会变化,因此 sustainment cost 持续存在。110 仅凭“旧”不能决定保留或废弃。

已发生的开发支出属于 sunk cost,但未来的 maintenance、security remediation、migration、parallel operation、data conversion、retraining、outage、rollback 与 regression risk 都是真实未来成本。CMU SEI 的 legacy modernization 研究同样要求针对大型复杂系统比较多种策略,包括 incremental modernization 与 coexistence。111

Google Android 给出了具体边界。Android 团队说明,重写既有数千万行 C/C++ 并不现实,因此优先让新代码使用 memory-safe language,并投资 Rust↔C++、Rust↔Kotlin interoperability。其 firmware 工作也记录了向既有 C codebase 渐进加入 Rust、优先处理新代码和高 security-risk component 的方法。112 这不是否定 Rust,而是说明full rewrite 与 incremental adoption 有不同 risk profile

FFI 与过渡期是独立的 cost center

渐进采用 Rust 必须维护与既有 C/C++ ABI 的边界。正如 6.2 节所述,extern "Rust" 与 default Rust layout 不能视为长期稳定 ABI,可能需要 C ABI、repr(C) 等显式 contract。102 此外还要设计 ownership transfer、allocator ownership、string/buffer lifetime、error mapping、callback、cancellation、thread affinity 与 panic/exception boundary。与 5.4 节错误模型一样,双方语言必须明确同一 failure 如何表达,以及谁负责 cleanup 和 retry。

“渐进采用更安全所以更便宜”和“既然存在 FFI 就应 full rewrite”都不是通用规则。边界少且稳定的 module 可能适合 selective replacement;如果 fine-grained crossing 遍布 hot path 或 ownership 频繁往返,performance、debugging 与 maintenance cost 可能反而上升。

变更策略是条件性选项,不是等级排序

策略 可能适用的条件 主要收益 主要成本或失败条件
加固既有实现 defect 局部且已验证 behavior asset 很大 transition 与 regression risk 较低 结构性 memory-safety risk 或 technical debt 可能保留
同语言 modernize 可先改善 architecture/test/observability 复用既有 ABI 与运维知识 safety rule 继续依赖 process 与 tooling
新功能使用 Rust 需要复刻的旧 behavior 少且 boundary 清晰 无需 rewrite 即可积累经验与 safety boundary 维护双 toolchain 与 interoperability
选择性替换高风险 module memory-safety exposure 集中且 interface 稳定 把 assurance 投资集中到高风险区域 FFI、data ownership、performance boundary 可能成为新 failure mode
full rewrite 既有 architecture 无法满足需求,且 specification、test、预算、cutover plan 足够 同时重设语言与 architecture schedule 超支、隐含 specification 丢失、parallel operation/rollback failure 影响大

大型、长期运行环境应针对每种策略追踪 migration 时长与 double-run cost、p95/p99 request 影响、peak memory、build/CI capacity、incident rate、rollback 时间、FFI crossing volume、duplicated tooling、security-patch latency、expert bus factor 与 multi-year support cost。即便 selective adoption 成功,boundary 也可能持续累积;rewrite 则可能长时间承担 old/new 两套系统的 operational complexity。

中间结论

对于 RQ3 与 RQ4,现有证据不能把 Rust adoption barrier 简化为固定的“人才不足”或“ecosystem 不成熟”。决策取决于组织实际 staffing capability、所需 dependency 的 assurance、legacy asset 与隐含 specification、FFI boundary、migration/cutover risk。Android 等大型既有 C/C++ codebase 已把 new-code-first 与 interoperability 用作真实迁移策略,full rewrite 只是多个选项之一。因此 Rust adoption 应依据在哪个变更单元能降低 defect、成本与 operational risk来决定,而不是追求某个代码转换比例。

7.4 “大型企业采用”叙事的多维分析:语境、限制与战略含义

Google、Microsoft、AWS 等大型技术企业在 production 中使用 Rust,是重要证据。但“企业 X 使用 Rust”可能把多个不同问题混为一谈:是否能 production deployment、特定 workload 观察到什么结果、组织内使用范围多大、Rust 是否造成这些结果、其他组织是否会复现。这些是不同命题。

因此本节把 corporate adoption 当作 case-study evidence,而不是 logo ranking。

案例 已确认的实际使用 该案例直接支持的范围 该案例单独不能证明的内容
Google Android Rust 用于 native system code、kernel/firmware 与 security-critical component new-code-first、interoperability 可在大型既有 codebase 中运行,并可测量 Android 内部 outcome 所有 Rust project 的 productivity/security 优势、Google 全公司标准语言、其他组织相同结果
Microsoft Windows Windows 11 24H2 的 win32kbase_rs.sys 实现 GDI region Rust 已随正式 Windows release 部署于 kernel component Windows kernel 全面迁移、一般 Rust-vs-C/C++ defect/cost ranking
AWS Rust 编写的 Firecracker 支撑 AWS Lambda 等 serverless 服务;EC2 对新 Nitro System component 使用 Rust Rust 可在高性能 isolation/infrastructure workload 中作为 production technology 运行 对全部 AWS workload 最优、其他规模与团队也有相同经济性

Google Android 的数字是强 case evidence,但 external validity 是另一问题

Google 2025 Android report 称,Rust code 的 memory-safety vulnerability density 比 Android C/C++ code 低约 1000 倍;相近规模的 Rust change 需要约少 20% 的 revision;code review 停留时间约短 25%;medium/large change 的 rollback rate 约比 C++ 低 4 倍。113 这些观察比“Google 也使用 Rust”更有信息量。

但不能直接把这些数字解释为 language-only causal effect。code 的角色、年龄、开发时期、team 构成与 review process 并非随机分配,Google 自己也提出 Android team 的 Rust expertise 增加可能影响 review-time 变化。因此这些资料强力支持在 Android 大型 production environment 中与 Rust adoption 同时观察到的 outcome,却不支持相同倍数会在其他组织普遍复现。

Microsoft 与 AWS 展示不同 adoption mode

Microsoft 的 Windows 11 24H2 documentation 明确记录 win32kbase_rs.sys 的 Rust GDI-region 实现。114 关键事实是 Rust 不再只是 research prototype,而是进入正式 OS release 的 kernel component。把一个 component 扩大为“Windows 已转向 Rust”会误读 adoption scale。

AWS 是另一种模式。Firecracker 是 Rust 实现的 microVM technology,用于 AWS Lambda 等基础设施;AWS 还说明 EC2 对新的 Nitro System component 使用 Rust。115 这证明 Rust 可在 virtualization、isolation、infrastructure workload 中 production operation,但不能代替 enterprise CRUD、data science、GUI、firmware、safety certification 等其他 domain 的 suitability 证据。

因此“大型企业采用”不是 homogeneous sample。Android 的 new-code-first、有限的 Windows kernel component、Rust-centric Firecracker/Nitro 在 adoption unit、legacy boundary、performance requirement、assurance goal 与组织投入上都不同。去掉这些条件只统计公司名称,就从 evidence 退化成 logo counting。

被选择的成功案例存在 selection effect

企业不会随机把语言分配给所有 module。它们更可能先在 memory-safety guarantee 或 predictable low-level control 有价值、可建立 component boundary、且能获得所需 expertise 与 tooling 的区域选择 Rust。因此成功 adoption case 支持“在这些条件下可行”“在这些条件下观察到这些 outcome”,但不会自动给出未选择 Rust 的 workload 的 counterfactual。

selection effect 也不意味着 case study 没有价值。production deployment 证明真实系统处理了 toy benchmark 无法展示的 build、incident response、dependency、upgrade、observability 与 staffing 问题。只是证据单位必须保持为具体 product、component、期间与 team,而不是整个公司

向其他组织迁移的是 mechanism 与条件,不是 logo

从 Google 的 new-code-first/interoperability、Microsoft 的 bounded kernel component、AWS 的 infrastructure-specific deployment 中,应提取的是变更 mechanism,而不是“大企业也用 Rust”的权威诉求:保留有价值的既有 asset,定义 boundary,建设必要 tooling 与 training,测量 security、rollback、review、latency、resource 等目标指标,再依据结果扩大或停止采用。

较小组织可能缺少专用 interoperability tool、compiler expertise、security-research capacity 或长期 training budget;反过来,小 codebase 与简单 deployment boundary 也可能让迁移更容易。不能仅由组织规模单调推断 adoption 难度。

第 7 章结论

综合本章证据,Rust 工业采用不能用“尚未成熟”或“大企业用了所以已经验证”这一条轴来概括。7.1 的 Linux 7.2.1 snapshot 显示 Rust source footprint 增长,并已有 Binder/GPU driver code,但在全部 source SLOC 中仍低于 1%;这一比例本身不测量 safety effect 或 adoption value。7.2 的 Ferrocene 表明,即使 Rust 语言未成为 ISO/IEC 标准,也可能存在 qualified toolchain 与部分 certification path;但 compiler qualification 不会自动认证所有 library 或最终 product。

7.3 表明 staffing、dependency assurance、legacy asset、FFI 与 cutover 条件塑造组织的 change strategy;7.4 则确认 Rust 能在 Android、Windows kernel component、AWS infrastructure 等不同 production 条件中运行。任何单一案例都不能独立确立 industry-wide prevalence、language-only causation 或所有 workload 的 comparative superiority。

对于 RQ3,adoption case 与 measurement 必须按照实际 unit 解读。production use 支持 feasibility;内部 longitudinal metric 支持该 environment 的 observed outcome;qualification 支持指定 assurance scope。把这些相加也不能自动推出 universal superiority 或未来 market dominance。

对于 RQ4,maintenance、same-language modernization、new-component Rust、selective replacement、full rewrite 是条件性策略,不是等级阶梯。应在同一 decision record 中比较 defect profile、code age、隐含 specification、interoperability boundary、staffing、assurance goal、migration 时长、rollback capability 与 long-term support。

在大型、长期和极端环境中,memory/resource headroom、p95/p99 latency、failure containment、patch latency、toolchain reproducibility、dependency replacement time、incident recovery、expert bus factor、certification evidence 保持、multi-year upgrade/rollback cost 可能比 adoption percentage 更直接。Rust 在 production 成功这一事实,与某个特定组织应迁移到 Rust 的结论之间,仍需要把 workload 与组织条件连接起来的比较证据。


第四部分:技术共同体话语分析

前三部分分析了 Rust 的语言保证、开发者体验、构建与部署成本以及产业适用条件。第四部分把分析单位从技术本身转向围绕技术公开提出的主张与论证模式。这里的核心问题不是喜欢或不喜欢某种语言,而是如何识别:带有条件的工程优势在何处被扩展为普遍性的技术选择命题、对其他方案的排除,或对人的地位判断。

本部分严格区分不同证据层级。Rust Project 的官方文档与 project goals 用作确认官方价值主张、保证边界与改进课题的一手资料。Reddit、Rust Users Forum、技术博客等公开帖子只作为证明某种论证形式确实可能出现的定性案例。本书目前没有预先定义、能够代表全部 Rust 网络话语的 corpus 或概率样本,因此不会从所选案例推断整个社区的频率、代表性或共识。58

同一测量、事件或帖子即使在后续章节再次出现,也不会被重新计作新的独立观察。技术事实与数值以首次完成审计的技术性论述为主,后续出现只作为对论证结构、综合判断或决策分析的再利用。因此,重复本身不会增加证据权重;更强的结论需要额外的独立证据。

同理,仅凭少量公开帖子不能判断作者的心理状态、群体认同强度、回音室是否存在、新开发者的技术选择是否改变,或组织采用是否受到因果影响。这些解释可以成为理解已观察论证的可检验假设,但若没有额外的访谈、实验、纵向资料、网络分析或定义明确的话语样本,就不能成为本书的经验性结论。一般研究也表明,源自 Web 的训练资料分布可能影响语言模型行为;但特定 Rust 话语相对于 Ada/SPARK 等其他方案究竟会在多大程度上使 LLM 回答产生偏向,仍是需要独立 corpus 与模型实验才能检验的问题。116

第 8 章在这些证据规则下分析本书称为“银弹叙事(silver-bullet narrative)”的论证形式。117 这一称呼既不代表 Rust Project 的官方立场,也不是对全体 Rust 用户心理的诊断。它是一个分析标签,用来指称这样一种推理模式:原本带有适用条件的技术优势丢失了这些条件,进而被加强为“唯一的解决方案”“在任何环境都是最佳选择”“其他变更策略没有意义”等结论。第 9、10 章随后综合技术选择与生态层面的含义,但不会把第 8 章尚未确认的频率或因果效果当作前提。

第四部分的目的不是评价某种技术或其用户,而是揭示主张的范围在何处发生变化,以及要证明这种变化需要什么资料

8. “银弹叙事”与集体防御机制的形成

第 8 章所说的“集体防御机制”不是临床或心理学诊断,而是对一种公开论证模式的统称:当批评或反例出现时,通过转移论点、改变比较标准、重新归类反例、判断对方资格等方式维护原有主张。某种模式是否存在于一个具体案例,与它是否普遍存在于整个 Rust 社区,是两个不同的问题。

本章把三个问题分开处理。第一,Rust Project 官方主张的价值和保证边界到哪里为止?第二,如果公开案例中出现了更强的普遍化、替代或地位判断,究竟加入了什么额外前提?第三,如果要讨论这些论证的频率、作者动机、受众效果或对技术选择的因果影响,还需要哪些额外证据?这一划分直接对应 RQ5,也就是如何把技术事实与修辞性泛化、地位判断区分开来。

8.1 节建立本章的证据边界和“银弹”分类标准。8.2 节考察“完全替代”和“只有重写才算改进”这种强变更策略;8.3 节讨论历史比较的使用范围;8.4、8.5 节分析对批评的回应以及资格、地位判断的具体论证。8.6、8.8 节把官方治理与改进活动同非官方话语区分开来,8.7 节则考察政府建议和企业案例究竟能支持何种范围的结论。

8.1 “银弹叙事”的形成过程及其效果

本节标题虽包含“形成过程及其效果”,却不意味着当前资料足以经验性地重建 Rust 网络话语的历史形成过程或社会效果。原因是本书没有预先定义的时期性 corpus、帖子纳入与排除规则、各平台曝光量以及受众资料。因此,本节首先区分已经确认的事实、定性案例、可能的解释假设和尚未测量的效果,并据此建立后续各节使用的判定规则。58

区分官方价值主张与非官方泛化

Rust Project 官方文档把 reliability/robustness、performance/resource consumption、long-term maintenance/extensibility 等作为目标;与此同时,2025 project goals 把在这三个维度中重视“两个以上”的项目描述为 Rust 可能成为有力候选的领域。同一目标文档明确列出 async Rust ergonomics、低层项目所需的 compiler/tooling、maintainer 协作等尚未完成的工作,2026 project goals 也继续列举具体问题与所需资源。RFC 和 project-goals 流程同样以提案、trade-off 审查、团队支持和资源限制为前提。118

这些资料直接表明,Rust Project 在提出强价值主张的同时,也处理适用条件和仍待改进的问题。因此,若要把“Rust 能解决所有系统编程问题”或“所有 C/C++ 系统都应该用 Rust 重写”归为Rust Project 的官方立场,就需要另行提供官方证据。本章不会在缺少这类证据时,把非官方帖子中的强烈措辞合并为整个项目的官方主张。

分析中不会把以下四个证据层相互替代。

证据层 资料能直接显示什么 单凭该资料不能说明什么
Rust 官方文档、RFC、project goals 官方价值主张、保证说明、改进课题与程序 全体 Rust 用户的态度、非官方话语频率
选取的公开帖子与讨论 特定语句和论证形式确实存在,以及该语境中的反驳 整个社区的代表性、多数意见、长期趋势
预先定义的 corpus 与 sampling 在定义的总体内测量频率、时期变化和平台差异 作者内在动机或因果效果本身
访谈、实验、纵向或网络资料 依设计而定,可研究动机、曝光、态度变化或传播路径的一部分 无条件推广到其他总体与时期

因此,即使后续各节引用强烈措辞,一个案例首先能证明的也只是“这种论证确实存在”。这种形式是否常见、是否代表 Rust 用户的群体认同、是否实际改变采用决策,仍是另外的问题。

被归为“银弹”的推理形式

本书并不把强烈陈述 Rust 优点本身视为问题。只要技术依据和适用条件得到保留,“Safe Rust 在编译阶段拒绝特定范围的 memory-safety 错误”“在某个新组件中采用 Rust 可能降低缺陷风险”“Cargo 的一体化工作流可能有利于某个团队”等都属于可以检验的工程命题。“银弹”分类只在从这些条件命题进一步发生如下额外推理时适用。

条件命题 更强的推理 额外需要的证据
Safe Rust 在定义范围内提供 memory-safety 保证 所以 Rust 在所有系统中都是最安全或唯一负责任的选择 包含其他风险类别、workload、FFI/unsafe、运行与保证/认证条件的比较
某组织的新 Rust 代码观察到良好结果 所以把现有系统全面重写为 Rust 一般都是最佳方案 包含替代策略、migration 成本、同步变更、长期维护与失败案例的比较
在所选公开案例中经常比较 C/C++ 与 Rust 所以其他语言被故意排除,话语议程已被掌控 定义明确的 corpus、比较对象选择原因、曝光量与受众资料
一些帖子对批评者作资格或地位判断 所以整个 Rust 社区都排斥批评 代表性样本、按平台和时期的频率、反例与 moderation 语境

如果右栏所需证据尚不存在,本书就不采用更强结论。反过来,仅选择少量批评 Rust 的案例就断言“Rust 没有实质优势”或“Rust 用户一般都不理性”,也是同一种错误。分析标准对支持与批评两个方向对称适用。

“形成过程”目前只是待检验模型

正如 2.3 节已确认的那样,一手文档能够证明 Rust Project 持续把安全性、性能、并发性、生产性与工具体验作为官方价值提出。30 但这些官方信息在非官方话语中被重复了多少、在重复过程中限制条件消失了多少、是否因此改变了受众的评价标准,是另外的经验问题。29

因此,本节把“官方价值主张 → 非官方重复 → 限制条件丢失 → 普遍化的选择命题 → 面对批评时的防御性反应”视为未来可以用 corpus 分析检验的模型,而不是已经证实的历史事实。每一个箭头都需要不同资料。仅分析官方文档频率不能证明非官方重复,非官方重复本身不能证明受众效果,一句激烈反驳也不能证明作者的心理动机。

对于 C/C++ 看起来经常作为比较对象、Ada/SPARK 较少出现的现象,也使用同一原则。像第 7 章的实际产业案例那样,当既有 C/C++ 代码与新 Rust 代码之间的变更策略本就是直接问题时,比较 C/C++ 可能在技术上十分自然。相反,要判断信息可及性、教育经历、市场曝光、刻意 framing 中哪一项对比较对象的选择贡献了多少,就需要定义明确的话语资料以及曝光、背景资料。不能只因为某个替代方案较少被提及,就把刻意排除或“争夺话语主导权”确定为原因。

心理与群体解释是竞争性假设,不是诊断

认知失调理论描述相互冲突的认知及态度调整的可能性,社会认同理论描述群体分类与内群体偏差的可能性。关于社交媒体回音室的研究也表明,不同平台的互动结构与同质性连接可能影响信息传播。119 但仅仅把这些一般理论的名称贴到一条 Rust 帖子上,并不能证明相应机制在该案例中发生。

例如,即使观察到某位作者投入大量时间学习 Rust,并对批评意见作出强烈反应,也不能据此把认知失调确定为反应原因。作者可能是在纠正技术误解,可能认为问题前提有误,也可能只是习惯使用强烈措辞。同样,几个意见同质的讨论也不足以证明整个 Rust 相关空间都是回音室。要提出这种主张,需要测量用户之间的连接、接触到的信息、互动同质性、随时间的变化以及比较平台。

区分对 memory safety 的官方强调与“议程掌控”主张

2.3 节已依据一手资料确认,Rust 官方传播一直把 memory safety、reliability、performance 等作为重要价值突出呈现。30 然而,“Rust 掌控了系统编程的 memory-safety 议程”或者“开发者因为 Rust 才开始把 memory safety 视为重要标准”,是包含受众重要性感知变化的更强命题。如果没有像原始 agenda-setting 研究那样把信息强调程度与受众认知连接起来的资料,本书能确认的只是官方强调以及这种信息确实存在29

因此,Ada/SPARK、GC 语言或现代化 C/C++ 在公开讨论中看起来相对较少,并不会被直接解释为 Rust “掌控议程”的效果。检验这一命题需要限定时期和平台的 corpus、按语言与主题划分的曝光量、搜索/推荐环境,以及受众调查或实验。当前它只是可以研究的假设,而不是本章的确定结论。

信息生态与 LLM 效果的边界

有一般性证据表明,Web 来源训练数据的分布和筛选可能影响语言模型输出的分布。116 但不能因此直接跳到“支持 Rust 的文本很多,所以 LLM 会高估 Rust”。首先需要测量 Rust、C/C++、Ada/SPARK 等相关技术在实际 corpus 中的占比与语境,确认模型使用过何种训练资料或定义可替代的评估 corpus,并在控制问题措辞与评价标准的条件下进行重复实验。

因此,本书只把 LLM 视为可能的二次信息路径。某个模型几次优先提到 Rust,并不能证明该模型训练资料的分布,也不能证明社区话语造成了因果影响。反过来,本书目前也没有证据断言这种效果不存在。当可以建立可复现的模型、prompt 与评价设计时,这个问题更适合作为独立研究课题处理。

中间结论

现有资料能够确认三点。第一,Rust Project 官方提出关于安全性、性能、可靠性、生产性等强价值主张,同时也讨论适用条件和尚未完成的改进工作。第二,后续各节选择的案例可用于检验:条件性技术命题扩展为普遍化、替代或地位判断这一论证形式是否存在。第三,这些形式的频率、整个社区的认同、作者心理,以及对新开发者、组织或 LLM 的效果,不能由当前 corpus 与研究设计确定。

这正是 RQ5 的边界。技术的实际保证和优势应按其自身条件评价;从这些优势跳到“唯一选择”或对人的资格判断时,额外前提应单独揭示;所选案例不能被推广到它没有证明的整个社区。下一节 8.2 将把这一标准应用于“完全替代”和“只有重写才算改进”的变更策略主张。

8.2 “完全替代”与“只有重写才算改进”叙事的局限

本节并不是预测未来 Rust 是否会在 C/C++ 的某些应用领域占据更大份额的市场预测,也不测量下述主张在公开话语中究竟有多常见。分析对象是把以下不同命题合并成一个结论时产生的推理跳跃

  • Rust 对某些缺陷类别提供更强的默认保证。
  • 某些既有系统可以从采用 Rust 中受益。
  • 在某些领域,Rust 的使用比例长期可能提高。
  • 因此,所有既有 C/C++ 系统都应该完全用 Rust 重写。
  • 因此,在同一语言内进行 refactoring、modernization、hardening 都没有意义。

前三个句子分别属于保证比较、条件性变更策略和未来采用预测,是不同命题。后两个句子则是覆盖所有系统和变更策略的强得多的处方。即使前三个命题成立,后面的结论也不会自动推出。本节使用的“完全替代”和“只有重写才算改进”并不是某个个人或 Rust Project 的直接引语,而是为了检验这种普遍化逻辑结构而构造的合成命题。如果要讨论它们在公开案例中的频率或代表性,仍需另行满足 8.1 节的 corpus 标准。58

1. 改写变更策略的名称会抹去选择空间

3.3 节把维护与缺陷加固、refactoring、modernization、selective replacement、新组件采用、full rewrite 定义为不同的变更单位。狭义 refactoring 是在保持可观察行为的同时改变内部结构;用另一种语言制作新实现则可能属于选择性替换或重写。45

因此,“C/C++ 真正的 refactoring 只有用 Rust 重写”这个合成命题首先改变了术语的类别。如果先把 refactoring 扩大为所有改进的总称,再把其中一种策略——语言替换——重新定义为唯一真正的 refactoring,结论其实已经被放进定义本身。这样,以下问题还没比较就消失了:

  • 现有行为与兼容性需要保留多少?
  • 风险是分散在整个系统,还是集中于某些边界?
  • 能否在同一语言中改善 ownership、interface、testability 与 observability?
  • 能否只用 Rust 写新功能,或只替换高风险 module?
  • 现有 architecture 本身是否阻碍需求,以至需要广泛重新设计?

答案不同,即使在同一 codebase 内也可能合理选择不同策略。先把策略名称压成一个概念,并不能代替实际比较。

2. “不是完整保证”与“没有效果”是两个不同命题

C/C++ 内部的 guideline、RAII、smart pointer、静态分析、sanitizer、fuzzing、隔离和 hardening 并不提供与 Safe Rust 相同的语言级 memory-safety contract。正如 3.3 节确认的那样,其中一些手段依赖 convention 与 toolchain 配置,动态分析只在执行过的路径上检测缺陷,instrumentation 还存在资源成本与 production 使用边界。46

但是,不提供与 Safe Rust 相同的保证,并不等于工程效果为零。 缩小 raw pointer 范围、明确 ownership 边界、在 CI 更早发现缺陷、隔离危险代码、改进 rollback 与 observability,都可能降低目标风险的发生概率或影响范围。这些效果是否足够,需要依据相应 threat model 与 assurance requirement 另行测量。

反方向也应采用对称标准。Safe Rust 在 sound 的 safe boundary 内能够强力预防特定 memory-safety 错误与 data race,但语言替换本身不会消除逻辑错误、resource exhaustion、deadlock、性能回退、功能遗漏、unsafe/FFI contract 错误、部署失败或 rollback 失败。如果要求 C/C++ 改进必须“消除所有风险”,却只凭某项语言保证的存在就把 Rust 重写视为已经充分证明整个系统成功,就是采用了不对称的证据标准

比较的核心不是完整性竞赛,而是针对同一 defect model 与运行目标,用相同指标评估各策略预防、检测或缓解哪些风险、程度多大,以及新引入哪些迁移风险

3. 语言保证与变更方式是两个独立维度

强语言保证有价值,与为了获得这种保证应修改多大范围、采用何种方式,是两个不同的问题。即使采用 Rust,也可以只用于新组件、selective replacement 一个狭窄 module,或选择更广泛的 rewrite。反过来,即使保留 C/C++,仍可 modernization architecture、ownership discipline、test、analysis 与 isolation。

Android 的官方 memory-safety 策略是同时使用这两个维度的实际案例:新 native code 优先选择 memory-safe language,同时继续对既有 C/C++ 应用 sanitizer、memory tagging 与 hardening,并把 Rust 与既有代码之间的 interoperability 作为投资对象。47 Firmware 案例同样记录了优先处理新代码和高安全风险既有组件的渐进式 Rust 导入。112

这些案例并不能证明“渐进采用总是最佳”的普遍规律,但它们提供了可能性证据,说明改善 memory safety 并不以先废弃整个既有系统为必要条件。反过来,正如 3.3 节的 bounded rewrite 案例所示,如果边界狭窄、需求和验证范围可控,且新实现带来的保证收益很大,那么组件级重写也可能合理。变更策略是条件性选项,不是成熟度阶梯。

4. Interoperability 既不是“注定永久共存”,也不是“必须全面重写”

原文曾较宽泛地表示,操作系统、驱动和库都把 C ABI 当作标准接口,因此 Rust 必须长期与 C 生态共存。这个范围过大。事实上,在很多把 Rust 与既有 C/C++ 代码、OS API、library 连接起来的 migration 中,C ABI 与 repr(C) 这样的明确 representation contract 确实是重要边界。但并非所有系统接口都能归结为一个 C ABI,而且这一事实本身也不能决定共存时间或最终 migration 形式。102

FFI 确实会产生独立成本。ownership transfer、allocator、buffer/string lifetime、error mapping、callback、cancellation、thread affinity、unwind/panic boundary 都需要明确定义;如果细粒度 crossing 广泛分布在 hot path 中,性能、debugging 与 maintenance 成本可能上升。但结论仍然取决于条件:

  • 边界狭窄且稳定时,selective replacement 与共存可能具有成本优势。
  • 边界过于复杂,或既有 architecture 阻碍新需求时,更大范围的 rewrite 反而可能更简单。
  • 对新组件而言,可以在无需复刻既有 behavior 的情况下直接采用 Rust。

因此,“需要 FFI,所以 Rust 无法替代既有生态”与“FFI 很麻烦,所以全面 rewrite 是唯一答案”方向相反,却都省略了必要条件。正如 7.3 节所述,实际判断单位应是 crossing volume、boundary stability、ownership contract、latency/resource budget、双 toolchain 维护成本与 rollback capability。

5. Legacy 应按未来风险与资产评估,而不是按年龄评估

“legacy”这个词也容易从描述变成价值判断。较老的实现可能积累 technical debt 与停止支持风险,但也可能积累 regression test、deployment 流程、data format、客户/设备兼容性、operational workaround、incident-response knowledge 等经过验证的资产和隐含 specification。软件 sustainment 研究指出,软件不是会物理磨损的物体;维护成本来自执行环境、需求、缺陷和性能条件的变化。110

因此,“因为老所以应该丢弃”和“因为长期验证所以不应改变”都不是充分命题。过去的开发支出可能是 sunk cost,但未来必须保留的 behavior、migration 与 parallel operation 成本、data conversion、retraining、outage risk 与 rollback risk 都是真实的未来成本。Legacy modernization 研究同样在大型复杂系统中按项目条件比较 incremental modernization、coexistence 与 replacement。111

因此,不应把 legacy 道德化为“坏东西”或“必须保留的东西”,而应把当前缺陷和支持状态,与未来 maintenance、transition 成本放入同一 decision record。从所用语言的年龄判断一个人的能力或责任感,并不能提供技术比较所需的证据。具体的资格与地位判断模式留到 8.5 节单独分析。

6. “完全替代”必须区分预测、处方与测量结果

“Rust 会替代 C/C++”这句话依语境至少可以有三种功能。

句子的功能 所需证据 本章判定标准
市场/生态预测:Rust 使用比例长期会增加 定义明确的 population、时间序列 adoption data、domain 划分、预测模型与不确定性 不仅凭部分企业案例或网络热度确定整个市场未来份额
项目处方:这个系统更适合大范围替换为 Rust 比较 defect distribution、assurance goal、specification/test 资产、interop、migration/rollback、性能/资源、staffing/lifecycle cost 必须在该项目条件下与其他策略比较
普遍命题:有意义的改进只有 Rust full rewrite 实质上覆盖所有相关 workload 和替代策略的极强比较证据 当前证据不支持,而且因排除反例可能性而属于过度泛化

7.3、7.4 节的 Android、Windows、AWS 案例说明 Rust 能在不同 production 条件中实际使用,Android 还记录了 new-code-first 与 interoperability 策略。但 production feasibility、特定组织的 observed outcome、adoption scale、language-only causation 和未来市场主导地位是不同命题。大型企业成功采用不能产生 full rewrite 的普遍处方,同样,某个 legacy migration 的困难也不能否定 Rust 长期采用的可能性。

在大型、长期运行和极端环境中,尤其应按策略追踪 migration 时长、old/new 双运行成本、p95/p99 latency、peak memory、build/CI capacity、incident recovery、security-patch latency、FFI crossing volume、duplicated tooling、expert bus factor、rollback 时间以及 multi-year support cost。相比“Rust 占百分之多少”,更直接的判断资料可能是:在什么变更单位上减少了什么风险,以及迁移过程一旦失败会付出什么成本。

中间结论

对于 RQ4,维护、refactoring、modernization、新组件 Rust、selective replacement 与 full rewrite 都是条件性策略,不是彼此否定的阶段。Safe Rust 强大的 memory-safety 保证可能成为选择性替换或重写的重要理由,但它本身不会自动决定变更范围或 migration 方式。

对于 RQ5,分析“完全替代”或“只有重写才算改进”时,需要明确从保证命题跳到变更策略、从特定案例跳到普遍处方、从技术评价跳到对人的地位判断时加入了哪些额外前提。如果使用所选公开案例,它们首先只能证明这种论证形式存在;没有定义明确的 corpus,就不能推断整个 Rust 社区中的频率或意图。

因此,本节结论既不是“full rewrite 是错误的”,也不是“Rust adoption 没有必要”。当前证据支持的更窄结论是:应把语言保证与变更策略分离,并用相同 defect model、运行指标和迁移成本比较不同方案。 下一节 8.3 将考察,把技术共同体的竞争叙事与历史案例比较时,哪些相似性有助于解释,类比又应在何处停止。

8.3 技术话语的历史先例:1990—2000 年代的操作系统竞争

本节的历史比较并不是为了证明“1990—2000 年代的 Linux 社区与今天的 Rust 社区在重复同一种群体行为”。当时的 hacker culture、GNU/free software 运动、open-source 运动、Linux 用户与开发者,以及 Unix 相关在线空间彼此有重叠,但并不是同一个总体。今天的 Rust 生态同样不能把官方项目、企业用户、library maintainer 与多个在线空间压缩成一种群体心理。因此,本节只把历史案例作为寻找相似论证结构的比较资料,而不把相似性本身当作当前 Rust 话语频率、原因或效果的证据。58

历史资料首先显示的是内部差异,而不是单一身份

即使只看 1990 年代末的 free software 与 open source,价值 framing 也不是单一的。GNU/Free Software Foundation 把 software freedom 与 community 置于规范性价值的中心。相比之下,Open Source Initiative 的官方历史资料记录,1998 年创造“open source”这一名称时,一个重要目的就是更有效地传达 source-sharing 的实用和 business-case 优势,并把这种 framing 与哲学、政治意味更强的“free software”标签区分开来。120 即使在更广义的 source-available 协作开发世界中,参与者对于应把什么放在核心价值位置也存在差异。

Eric S. Raymond 的 The Cathedral and the Bazaar 同样没有把 Linux community 描述成一个声音,而是用 bazaar 比喻一个包含不同 agenda 与 approach 的开发世界。121 这并不意味着当时公开话语中没有强烈叙事或身份表达,而是说明更安全的同时代资料解读应当是:不能仅凭“Linux community”这一名称,就让一种价值、态度或论证代表整个群体。

M$RTFM 是有文献记录的文化标记,但代表性是另一个问题

The Jargon File 4.2.2(2000)作为当时 hacker slang 的历史 snapshot,把 M$ 记录为 Microsoft 的网络缩写,把 RTFM 记录为 Unix hacker context 中对被认为过于简单或令人厌烦的问题可能使用的表达。同一文档的导言把 hacker culture 本身描述成具有共同 roots 与 values、但联系较为松散的多个 subculture,并说明 slang 可以成为 inclusion 与 exclusion 的标记。122

这份资料支持的推断范围有限。可以据此记录:M$RTFM 这样的表达确实存在于当时部分技术文化中,技术语言也可能承担表达归属与边界的功能。但不能由此推出“多数 Linux 用户把 Microsoft 当作道德敌人”“排斥新手是 Linux 社区的一般规范”“CLI 用户系统性地把 GUI 用户视为低等”等总体层面的命题。要提出这些主张,需要针对 mailing list、Usenet、forum 等建立定义明确的历史 corpus 与 sampling。

历史类比可以比较的是主张如何转变,而不是人的性格

把今天的 Rust 话语与过去的操作系统、FOSS 话语相比时,相对安全的比较单位不是某个群体的性格,而是带条件的技术命题如何转变成更广泛的价值、身份或地位命题。即使时代与技术不同,下列结构仍可用于分析。

可比较的论证结构 历史资料能够显示什么 不能自动转移到 Rust 话语的结论
技术属性与价值语言结合 freedom、community、pragmatic development model 等多种价值框架确实与技术选择结合 Rust 用户具有相同的价值或身份结构
群体内部 shorthand 表达归属或边界 hacker slang 中记录了 inclusion/exclusion 功能,以及 M$RTFM 的用法 当前 Rust 空间存在同样强度或频率的 gatekeeping
竞争技术被用作叙事中的比较对象 proprietary/open development、Microsoft/open source 等对立 framing 有文档记录 Rust 与 C/C++ 的比较由相同历史原因或动机形成
未来展望可能与当前技术评价混合 历史运动和组织存在明确追求 adoption 与 diffusion 的资料 当前 Rust 的未来 market share 或整个社区的乐观程度

因此,历史资料可以帮助建立可能的论证 mechanism 与分类标准。但“过去也这样,所以 Rust 也是这样”的推理,会把历史类比本身变成它无法提供的证据。

差异很大之处必须停止类比

1990—2000 年代的操作系统/FOSS 竞争与当前 Rust adoption 首先在技术单位上就不同。操作系统竞争涉及 kernel、userspace、driver、application ecosystem、distribution 与 hardware support 结合而成的平台竞争。Rust 则是可以部分引入多个操作系统,并与既有语言、library 共存的 programming language,因此能够采用 8.2 节讨论的 selective replacement 与 new-component adoption。把一个 desktop OS 换成另一个 OS 的迁移成本,不能与在一个 codebase 中把部分 module 改用另一种语言实现的迁移成本视为同一个单位。

组织结构与媒介环境也不同。1990 年代的 Usenet、mailing list、hacker lexicon,与今天的 Reddit、social media、corporate engineering blog、Foundation governance 在曝光与 moderation 结构上不同。正如 GNU、OSI、Linux kernel、distribution community 是不同组织一样,Rust Foundation、Rust Project governance、企业采用 Rust,以及个别 online forum 中的发言,也都是不同的证据单位。把一个历史表达直接映射成今天 Rust 的官方立场或整个用户文化,会抹掉这些差异。

因此,本节不会把 cognitive dissonance 或 social identity 一类心理 mechanism 从历史案例“移植”到今天。即便过去和现在观察到相似表达,它们是否来自同一心理原因、是否产生同样的 community-level effect,仍是独立的研究问题。

中间结论

对于 RQ5,历史先例的作用有限但有用。同时代资料表明,1990—2000 年代 hacker、free-software、open-source、Linux 周边确实同时存在技术主张、价值 frame、group shorthand 与竞争叙事;同一批资料也显示,这个世界由多个 subculture 以及不同的哲学、实用 frame 构成。

因此,本书不会从过去案例推断今天 Rust 社区的心理或话语频率。历史材料只作为比较工具,用来寻找诸如 技术事实 → 价值命题 → 普遍选择命题 → 对人的地位判断 这样的主张范围变化。建立这一历史边界之后,下一节 8.4 的公开讨论案例同样应被视为分析单个论证结构及其可反驳性的定性资料,而不是“过去相同群体行为”的证据。

8.4 对回应批评的话语论证模式分析

按照 8.1 节确立的证据规则,本节不会依据少量公开案例推断整个 Rust 社区的反应频率或心理状态。分析单位是:针对主张 A,回应 B 是否真正反驳了同一个命题,还是转移到了范围、比较标准或对发言者的评价。如果能够确定公开案例,就把可核实事实与参与者评价分开;没有直接来源的句子则明确标为用于检验论证结构的合成示例,而不是某个具体个人的原话。58

同时,并非所有范围限定都是回避论点。例如,如果原始主张是“Rust 的 memory-safety contract 是否失效”,那么“这个漏洞不是 memory-safety vulnerability”就是直接的范围校正。但如果原始主张是“这个 safe API 能否产生严重 security flaw”,仅重复前一句并没有回答安全影响。因此,本节不会先贴上谬误标签,而是先区分原始命题、回应实际处理的命题,以及回应之后仍未解决的命题

8.4.1 Linux 7.2.1 中 Rust 的占比:测量值与重要性判断分离

7.1 节对最新 stable 的重新测量显示,Linux 7.2.1 source tree 中 Rust SLOC 为 114,481 行,占总计 30,518,591 SLOC 的约 0.375%。这个数字直接证明的只是:按已说明的 cloc v2.04 步骤,对该 tarball 得到的 source-tree composition106

因此,下面两个命题可以同时为真:

  • “当前 stable kernel source 中 Rust 的量化 footprint 低于 1%。”
  • “即使 source footprint 很小,在特定 driver 或 security boundary 中也可能具有重要技术作用。”

若针对第一句回答“Rust code 位于重要 subsystem,所以 SLOC 没有意义”,这与重要性有关,但并没有反驳 SLOC 测量本身。反过来,仅从 0.375% 推断“Rust 在 kernel 中不重要”或“未来不会增长”,同样超出了测量范围。

引入 Google、Microsoft、AWS 等其他 production Rust 案例也适用同样原则。这些案例支持“Rust 可以在 production 中运行”这一不同命题,却不会改变 Linux 7.2.1 的 source 占比。如果原问题是“Rust 是否用于 production”,这些案例可以构成有效反例;如果问题是“这个 kernel snapshot 中 Rust 占多少”,则论题已经发生变化。

攻击测量者偏好的语言或动机也不能证明测量方法有误。像“测量者是 Ada 用户,所以这个数字不可信”这样的合成示例,如果没有指出 artifact、checksum、tool version 或 counting rule 的具体错误,就仍然只是对发言者的评价。相反,如果给出不同的可复现结果,或证明 cloc 的分类方式不适合该问题,那就是正当的方法论批评。

8.4.2 memory leak:保证边界与运行严重性分离

Rust Reference 明确把 memory/resource leak 和 destructor 未执行列入不被视为 unsafe 的行为,std::mem::forget 也是 safe function。Rust Book 还说明,使用 Rc<T>RefCell<T> 可以在 Safe Rust 中形成 strong-reference cycle 并造成 leak。41 因此,“这个 leak 不违反 Rust 的 memory-safety contract”在技术上可以是正确的。

但对于长期运行服务,retained object 是否会导致 OOM、latency 增加、restart 和 availability 下降,是另一个运行层问题。把论证扩展成“因为 memory-safe,所以不构成问题”,就是混淆保证范围与运行严重性。反过来,存在 leak 也不能说明 Safe Rust 对 use-after-free、invalid access 等问题的保证没有意义。

“开发者本来应该使用 Weak<T>”的责任讨论也要分成两层。某个 reference cycle 的直接原因确实可能是 application design;但 API 是否容易形成 cycle、observability·quota·restart policy 是否充分、library design 能否进一步降低风险,都是独立的 system design 问题。责任归属不会使运行风险消失。

8.4.3 rav1d/dav1d:安全范围、性能归因与维护三个问题

rav1d 不是假设案例,而是可以追踪实际公开争议的项目。2023 年,ISRG 的 Prossimo 与 Immunant 合作启动 rav1d,把 VideoLAN 的 C 版 AV1 decoder dav1d 移植到 Rust。官方目标是把 dav1d 的 C code 迁移到 Rust 以提高 memory safety,同时为了性能保留现有 native assembly,保持与 dav1d 的 drop-in C API compatibility,并使 assembly 与 upstream 变化便于频繁同步。123

Prossimo/Immunant 在 2024 年的技术报告明确说明,dav1d 中大量性能关键的低层操作由 native assembly 实现,因此 rav1d 对其进行了复用。同时,报告指出即使启用全部可用 assembly,decoding runtime 中仍有大约一半由 Rust code 占据,并记录了把 C2Rust 产生的 unsafe 代码逐步改写为 safe、idiomatic Rust,同时分析 bounds check、threading model、buffer ownership 等成本的过程。123 因此,“rav1d 的性能全部来自 Rust”和“Rust 部分对性能毫无贡献”都比官方证据更强。

2025 年,Prossimo 报告 rav1d 能通过与 dav1d 相同的 test,也能在 Chromium 中运行,但当时依据 benchmark、input 和 platform 不同,大约慢 5%,并公开了用于缩小性能差距的 $20,000 bounty。同年 rav1d 1.1.0 还明确记录:通过 backport dav1d 1.5.1 的性能改进来完成同步。124

围绕这一结构,公开讨论中实际出现了三类批评:第一,在 unsafe boundary 上复用 native assembly 时,“memory-safe decoder”这一称呼的保证范围应到哪里;第二,需要持续把 dav1d 改进 backport 到 rav1d 的维护模式能否长期持续;第三,独立 fork 是否能长期保持 codec expertise 与快速 upstream bug response。125 这个公开案例只能证明这些问题确实被公开提出过,并不代表 FFmpeg、VideoLAN 开发者整体,也不代表 C 或 Rust 社区的共识。

这个案例最重要的是不要把三个不同问题合在一起。安全性问题询问迁移到 Rust 的 parser·control code 与剩余 assembly/FFI boundary 各自满足哪些 memory-safety invariant。性能归因问题询问 Rust、复用的 assembly、algorithm、compiler、threading 与 optimization 各自对结果贡献多少。维护问题则涉及 upstream 同步成本、fork ownership、codec expertise 与 support horizon。

因此,“因为复用了 assembly,所以 Rust port 的安全价值为零”忽略了把 parser 与 higher-level C code 移到 safe Rust 的效果。反过来,也不能把“memory-safe Rust decoder”解释成覆盖 assembly 与所有外部边界的无条件保证。Prossimo 自己明确说明 assembly 仍作为 unsafe native routine 保留,因此更准确的说法是:大幅减少 memory-unsafe C 区域,同时保留性能所需 native-assembly boundary 的移植123

同样,对 upstream 成果归属与协作伦理的批评属于与性能、安全测量不同的层次。rav1d 基于 dav1d 并复用 upstream assembly 与变更,这一事实本身是公开且明确的。这样的复用是否得到恰当 credit、署名是否充分、funding/maintenance model 是否长期理想,还需要 governance 与价值判断。“非对称贡献结构”或“知识诚实性”等评价必须明确其前提,标签本身不能代替 benchmark 或 memory-safety 证据。

8.4.4 std::process::Command CVE:区分 memory safety 与 security

Rust Security Response WG 在 2024 年披露的 CVE-2024-24576 涉及 Windows 上 std::process::Command 对 batch file 参数的 escaping 不充分;在攻击者能够控制 argument 的条件下,可能导致任意 shell command 执行。原问题在 Rust 1.77.2 中修复,之后又报告了独立的缓解绕过问题 CVE-2024-43402,并在 Rust 1.81.0 中补充修复。44

“这不是 memory-safety vulnerability”作为缺陷分类是正确的。这个问题不是 buffer overflow 或 use-after-free,而是 command argument/API contract 的逻辑性 security flaw。但如果问题是“Safe Rust API 是否也可能包含严重 security bug”,只重复 memory-safety 边界并没有回答完整问题。

反过来,也不能从一个 CVE 推断 Rust 的 memory-safety contract 已经失败。更准确的结论是:memory safety 只是 security 的一个子集,safe API 仍可能错误实现 shell escaping、authorization、protocol 或 state-machine logic 等其他安全契约。

8.4.5 Linux Rust Binder CVE:unsafe 边界与责任归属

CVE-2025-68260 是一个实际案例:Linux Rust Binder 在处理 death_list 时,unsafe list removal 与 concurrent access 条件不匹配,导致 data race 与 pointer corruption。该缺陷影响 Linux 6.18,并在 6.18.1 与 6.19 系列中修复。107

“语言规范本身没有把 data race 变成 safe behavior”和“Rust abstraction 的 unsafe proof obligation 在实际 implementation 中失败”可以同时成立。unsafe 不是出现缺陷后就把它排除在 language/library design 评价之外的免责标记,而是表示某些 compiler 无法直接验证的 invariant 必须由人承担。

如果只把责任归于某个开发者,并以“因此与 Rust design 无关”结束,就仍留下 reviewability、abstraction boundary、synchronization contract、regression test 等 system-level 问题。反过来,从这一个 CVE 推断“Rust kernel code 与 C 一样 unsafe”则需要 matched workload 与 defect denominator。两种推论都超出了案例直接支持的范围。

8.4.6 “除了 Rust 没有其他选择”:遗漏候选集合与需求

下面不是某个具体个人的直接引语,而是把公开技术讨论中可能出现的结构压缩成的合成命题

合成示例:“在无法随意决定 deployment environment 的真实项目中,C++ 不能用。因此除了 Rust 没有其他选择。”

第一个前提在某个具体项目中确实可能足以排除 C++。但是,排除一个候选并不意味着其他所有候选都被排除。 要证明“唯一选择”,至少必须明确 workload、latency·memory·real-time 要求、是否允许 GC/VM、binary·deployment 条件、认证要求、现有 ABI/library、support platform、人员与 lifecycle 条件,并对现实候选集合使用同一标准。

允许 managed runtime 的 backend 或业务系统、需要无 GC native executable 的 low-level software、要求强 run-time check 或 formal proof 的 safety system,其候选集合并不相同。对于已有大量 C/C++ asset 的系统,同语言 modernization、高风险 module 的选择性 Rust replacement、mixed-language architecture 也都是候选。因此,“真实项目”不是需求,而是可能掩盖不同 domain 的修辞分类。

更准确的命题应当是有条件的:如果项目同时要求无 GC native execution、强静态 memory safety、目标 platform support 与组织长期维护能力,而且其他现实候选都无法满足这些条件,那么 Rust 可以成为最强的选择。但在完成这种比较之前,应区分有力的候选唯一的替代方案

8.4.7 评估回应的共同步骤

与其把以上案例合并成单一“Rust 防御模式”并推断其频率,不如对每个具体回应按以下顺序进行可复现的判断。

步骤 问题 判断示例
1. 固定原始命题 实际主张的是什么? 分离 source 占比、memory-safety contract、整体 security、运行 severity、migration suitability 等
2. 确认回应命题 回应是否处理同一个命题? 区分 scope correction、提出另一项优点、评价发言者
3. 确认证据单位 是 artifact、官方 advisory、benchmark、case 还是 opinion? 分离测量与解释、官方事实与参与者价值判断
4. 检查比较标准对称性 正反双方是否使用相同 denominator 与标准? 检查例如对 C/C++ 要求整体 security、对 Rust 却只按 memory safety 评价的非对称
5. 记录未解决命题 回应之后还有什么未回答? 运行影响、causal attribution、external validity、maintenance cost 等

本节中的 red herringad hominem、genetic fallacy 等名称是分析之后的总结标签,而不是判断起点。在某些专业问题中,发言者的知识水平确实可能影响 evidence quality;其他公司的 deployment 也可能是针对原始普遍命题的直接反例。脱离上下文,仅凭一个表达就宣布某种谬误,会重复本书所批评的过度概括。

中间结论

对 RQ5 而言,关键不是回应批评时语气强还是弱,而是论证范围如何移动。Linux 的 0.375% 是 source composition;memory leak 是不同于 memory-safety UB 的 operational risk;rav1d/dav1d 争议必须分开处理 safety scope、performance attribution 与 fork maintenance;Command 与 Binder CVE 则分别展示 logical security contract 和 unsafe proof obligation 的边界。

这些案例既不否定 Rust 的优势,也不能证明 Rust 社区普遍具有防御性。反过来,出现“按定义就是 memory-safe”“大公司也在使用”“这是开发者错误”等句子,也不会自动使原始批评失效。必须逐项分析:回应真正反驳了原始命题的哪一部分,又把哪一部分转移到了不同层次。

下一节 8.5 将单独考察这种论证移动超出技术本身、转变为对发言者资格、正常性与智力等地位判断的情况。

8.5 技术选择的地位化:资格、正常性、智力等级与话语排除

在技术讨论中,发言者的经验和专业能力可以帮助判断证据所支持的范围。评估某种语言在什么条件下是更强的选择,以及某个人是否具备实际使用该语言的能力,也属于正当的工程判断。但是,当技术优势被转换为选择该技术者的一般优越性,并被用作贬低非使用者智力、资格或正常性的依据时,讨论便从技术评价转向对个人和群体地位的判定。

本书把这种转移称为技术选择的地位化。这并不是一个得到广泛共识的单一心理学术语或形式谬误名称,而是用于分解技术话语中可能出现的下列连续过程的描述性范畴。由于本书目前没有能够估计这一过程频率或代表性的预先定义 corpus,下面各阶段是论证分类框架,而不是关于整个共同体的经验性顺序模型。

  1. 某种技术的条件性优势被扩大为普遍优越性。
  2. 理解或选择该技术的事实,被用作用户在智力或职业上优越的标志。
  3. 非使用者不再只是处于不同条件而作出不同选择的人,而被分类为无知或落后的外群体。
  4. 技术反论不按其内容审查,而被解释为发言者的低下、恐惧、沉没成本或理解不足。
  5. 当反对和不快也被吸收为确认既有地位分类的证据时,论证便形成自我封闭结构。

本节不推测特定个人的性格、精神状态或临床特征。分析对象是能够从公开语句中辨认出的分类标准、举证责任与论证结构。本节采用引语形式的句子也不是某个具体个人的逐字原话,而是为了明确逻辑移动而重构的合成示例(composite example)。因此,合成示例不是实际频率、代表性或 Rust 用户整体态度的证据。使用真实公开案例时,仍然适用 8.1 节的 sampling boundary。58

1. 区分专业性审查与排除发言者

指出专业知识不足,并不总是守门。对于特定 unsafe 代码的健全性、编译器实现或操作系统内核接口等需要高度专业知识的问题,确认相关经验和证据质量是正当的。不过,在以下情况下,专业性审查可能不再是评价论点的手段,而变成排除发言者的装置:

  • 仅根据与批评内容无关的所属组织、惯用语言或职称否定主张;
  • 不检查所提交的资料或可复现结果,直接以资格不足作结论;
  • 只有在反例出现后,才重新设定“真正的开发者”或“真正的系统编程”的标准;
  • 对质量相当的证据,向支持者和批评者适用不同的专业性标准。

合成示例:“你的项目没有自行实现事件循环或调度器,所以不是真正的系统编程。因此,你关于生态和生产率的经验没有评价价值。”

这种回应没有先说明评价该问题究竟需要何种经验,而是把发言者的工作排除在相关类别之外,从而消除批评的效力。不过,并非所有范围划分都属于“真正的苏格兰人谬误(No True Scotsman Fallacy)”。这一谬误通常要求先对某个群体作出一般化陈述,随后出现与该一般化相冲突的反例,再为排除反例而任意缩小群体定义。126 如果无法确认这种先行的一般化和事后的重新定义,该发言仍可能构成守门或不正当的范围限制,但不应立即断定为“真正的苏格兰人谬误”。

2. 技术优越性与用户地位的结合

某种语言在特定条件下比其他选择更安全或更有生产率,并不包含对用户个人一般智力或人格价值的判断。关于技术的命题与关于选择该技术之人的命题,需要不同的证据。下面的合成示例检验从技术的条件性优越 → 用户的一般性优越这一移动。

合成示例:“有能力理解这门语言根本原理的开发者,最终都会选择它。坚持其他选择的人,要么思维水平较低,要么被过去的职业经历所束缚。”

在这种结构中,技术优越性与用户优越性以循环方式相互保证:因为是优越的人,所以选择优越的技术;因为选择了该技术,所以被归为优越的人。然而,语言选择可能随需求、既有代码、人员、工具、认证、部署环境、实时约束、迁移成本和组织风险容忍度而变化。理解同样事实的开发者,在不同条件下仍可能得出不同结论。

当技术开始充当用户地位标志时,技术批评的意义也会发生变化。对语言性能、安全保证或生态的批评,可能不再被理解为审查某项主张的适用范围,而被解释为否定选择该语言的用户及内群体的洞察力、先驱性和职业价值。在这种解释前提下,回应可能从技术反论转移到评判批评者的资格和心理。当前资料无法估计这种移动的频率,也不能证明它在 Rust 话语中呈增长趋势。

这种分析并不把强烈的技术偏好或社区归属感本身视为问题。如果在积极推荐技术的同时明确适用条件和反例,并独立评价非使用者的能力和价值,那么技术主张与用户地位仍然分离。问题发生在一种技术选择被用作衡量整个人之等级的替代指标时。

3. 正常性的规定与内外群体的构造

本书把在缺乏独立依据的情况下,将某一生态的惯例作为普遍规范的修辞模式,描述性地称为“规定正常性(defining normality)”。它并不是一个得到广泛共识的单一形式谬误名称。

“正常”“标准”“常见”等词本身并没有错误。如果根据国际标准、明确的组织规则、市场占有率、兼容性要求或经过测量的使用频率来限定范围,它们可以成为有用的技术描述。问题发生在评价标准和总体范围没有说明,却把发言者熟悉的生态选择说成所有语言和组织都应遵循的默认值时。

合成示例:“正常的语言就应当以同一种既定方式提供构建、包管理、代码分析和编辑器支持。无法接受新标准的开发者已经属于落后的一代。”

这个示例在同一段话中把技术配置的正常性与用户的正常性结合起来。第一句提出工具配置标准,第二句则把不遵循该标准的人归入落后的外群体。此时,“正常”“现代”“真正”“负责任”等词不仅描述技术属性,还承担规定内群体资格和外群体缺陷的作用。

现实开发环境同时存在以集成 IDE 为中心、以独立语言服务器为中心、以命令行工具为中心以及组织内部平台为中心的模型。各模型在安装便利性、自动化、可替换性、离线运行、长期支持和组织控制方面具有不同成本。因此,应比较的是何种选择适合哪些用户和运行条件,而不是宣布某一种工具配置或语言能够普遍证明其用户现代或正常。

4. 区分语言熟练度、认知效果与工作绩效

下面的合成示例检验一种把学习特定语言的能力或意愿直接连接到一般智力及程序员职业胜任力的命题。

合成示例:“没有能力学习 Rust,或者不愿意学习 Rust 的人,最终也不具备职业程序员的资格。”

这一主张把四个不同问题合并为一个问题。

  1. 学习与认知任务迁移:编程教育不仅包括语言概念和工具的学习,也包括部分问题解决策略。综合 105 项研究和 539 个效应量的元分析报告,编程学习具有中等程度的总体迁移效应(g = 0.49)和远迁移效应(g = 0.47)。这支持编程教育可能对某些认知任务产生积极影响。127
  2. 一般智力与人的等级:特定任务成绩提高或学习迁移本身,并不能证明心理测量意义上的一般智力全面上升,也不能证明学习者与非学习者之间存在人格或职业等级。更强的结论需要独立的测量和研究设计。
  3. Rust 特有效果与选择效应:上述元分析综合了多种编程语言和教育环境,并没有检验 Rust 独有的认知效果。同样,即使自愿选择 Rust 的群体表现出更高的既有知识或技术兴趣,也必须控制教育机会、工作经验和自我选择,才能断定是语言学习造成了差异。
  4. 工作相关性:当编写和维护 Rust 代码是核心工作时,Rust 熟练度或学习能力可以成为直接的选拔标准。对于其他语言、领域或职能的岗位,则应分别评估设计、调试、测试、运维、安全、协作和领域知识等实际工作所需能力。作为一个方法论参考,美国《雇员选拔程序统一指南》要求把选拔标准的效度与重要工作任务及其所需知识、技能和能力相联系,而不能仅凭声誉或轶事假定其有效。128

因此,“熟练使用 Rust”可以证明某些与 Rust 有关的能力,但其本身并不能代表所有软件开发工作的绩效或一般智力。反过来,尚未学习 Rust 或在学习中遇到困难,也不能据此否定一个人成为程序员的可能性。

5. 技术反论的心理化与动机推测

认知失调、社会认同、沉没成本等心理与社会解释,可以作为解释技术选择的竞争性假设。但正如 8.1 节所区分的,存在一般理论并不能证明某个 Rust 发言者的具体动机或共同体层面的机制。119 要判断教育、代码、职业投入或对新技术的不确定性是否影响了某次具体决策,需要关于该人物与情境的额外资料。仅凭动机推测也不能否定反论内容。

合成示例:“他们无法承认旧语言的局限,是因为害怕过去投入的职业经历和代码变得毫无价值。他们提出技术理由,但真正的动机只是维护自身地位的抵抗。”

这种回应没有审查性能、生产率、生态、认证、招聘和既有系统集成等争点,而是用对发言者动机的推测加以替代。即使沉没成本或地位防卫在一定程度上存在,也不能因此证明“应维护既有系统或渐进迁移”的技术主张为假。动机是否存在与主张内容真假,应分别评价。

动机推测还必须对称适用。如果不能仅因批评者投资于既有技术而否定其主张,也不能仅因支持者投资于新语言的学习、项目、声誉和群体身份而否定其主张。无论哪一方,都应先检查代码、测量结果、成本、风险和适用范围。

6. 偏好技术的普遍化与重复认可

当技术选择与用户地位结合时,某项技术的实际优势可能被扩大到原有适用范围之外。内存安全方面的强项可能被推导为“它应成为所有软件的默认语言”,某项服务或新组件的成功可能被推导为“所有既有系统都应重写”。此时,偏好的技术不再被当作多种工程手段之一,而被当作可反复应用于各种问题的默认答案。

合成示例:“安全、性能、生产率、可维护性和开发者水平的问题,最终都来自同一个原因。把这门语言设为默认值,就能同时替换落后的技术和落后的思维方式。”

不同问题需要不同的比较标准和证据。内存安全、吞吐量、延迟、可认证性、开发生产率、人员供给和遗留系统集成,不能缩减为单一指标。把一个领域的强结果转移为另一个领域的优越性,需要补充证据。产业案例和政策资料的适用范围将在 8.7 节另行审查。

如果假定某个空间里同一主张和地位分类被反复认可,就可以分析这种重复是否会被当作主张本身的证据。但本书并未测量 Rust 相关空间中的 network homophily、exposure 或 echo-chamber 程度。119 因此,本书不预设真实内部共识的规模或重复频率,只应用一条规则:观察到的同意必须与独立的技术验证区分。

7. 自我封闭论证

本书所说的自我封闭论证(self-sealing argument),是指把反对证据和反应也吸收为原有结论的进一步证据,从而使任何观察都无法削弱结论的论证结构。这里使用这一名称是为了进行描述性分析,并不意味着所有心理动机推测都会自动构成同一种错误。

合成示例:“智力正常的程序员都会承认 Rust 的优越性和学习价值。反对的人是缺乏理解能力,而对这种评价感到不快,恰恰证明他知道自己的低下。”

这一论证具有如下封闭结构。

  1. 预设结论:把 Rust 的普遍优越性和支持者的正常性当作分类前提,而不是需要检验的结论。同意成为正常的证据,反对成为低下的证据。
  2. 技术与用户地位的循环保证:因为是优越的人,所以选择 Rust;因为选择了 Rust,所以被归为优越的人。两者都没有经过独立测量的检验。
  3. 把技术反论心理化:性能、生产率、生态、认证、招聘或与既有系统集成等反论,被替换为对自卑、恐惧、沉没成本或抵抗等动机的推测。
  4. 消除可证伪性:如果反对、不快、漠不关心以及尝试说明都被解释为同一结论的证据,任何观察都无法使主张得到修正。
  5. 不对称的举证责任:要求批评者承认该语言的全部优点并克服学习障碍,却不要求主张优越的一方提供比较资料、适用范围和失败条件。
  6. 混淆条件性技术判断与人的等级:在内存安全和性能同时重要的领域,Rust 可以是强有力的选择,在这些条件下承担学习成本也可能值得。但这不能推出所有程序员都必须选择同一种技术,也不能证明不同选择意味着智力低下。

8. 审查地位化主张的标准

评价技术讨论中有关资格、正常性或用户地位的主张时,需要区分以下问题:

  • 判断该主张真伪实际上需要哪些专业知识?
  • 该专业性标准是否在反论出现之前已经说明?
  • 是否独立于发言者背景,检查了代码、资料、测量结果和复现步骤?
  • 关于技术优势的证据,是否真的测量了用户的一般智力或职业优越性?
  • 是否没有从需求和成本出发,而只用无知、低下、恐惧或沉没成本解释非使用者的选择?
  • 是否对支持者和批评者适用相同的证据、专业性和动机推测标准?
  • 是否有额外证据把某一领域的成功扩大到其他问题和所有既有系统?
  • 是否区分了内群体的重复同意与独立技术验证?
  • 出现什么反例或结果时,会修改现有判断?
  • 如果评价语言熟练度,它与该岗位的重要工作任务有什么联系?

总之,专业能力、标准、语言熟练度和技术建议都可以成为正当的评价因素,但必须说明其适用范围和证据。把某种语言的优势转换为其用户的一般优越性,把非使用者分类为低下的外群体,并仅用发言者的缺陷解释反对意见的话语,会在检查技术事实和工作相关性之前先决定人的地位。

技术不是替代性衡量用户智力或人格价值的标志。承认强有力的技术成果,与拒绝把这些成果扩大到所有问题、所有组织以及所有开发者的等级并不矛盾。分离技术选择地位化现象的目的,不是贬低某个具体社区,而是把条件性的工程判断还原为可验证的主张。

8.6 2023 年商标政策争议与治理思考

2023 年 Rust 商标政策争议不能准确地简化为“基金会单方面强推政策,随后因社区反对而撤回”。按官方记录的时间线,草案制定、公开 consultation、反馈与程序批评、长期修订、最终批准是不同阶段。本节不会把公开反应的数量当作代表整个社区的投票结果,而是考察每个阶段由哪个组织承担什么责任,以及相关组织自己承认了哪些问题。

8.6.1 2023 年文件是 consultation 草案,而不是已经实施的政策

Rust Foundation 在 2022 年启动商标政策 review 与 survey,并于 2023 年 4 月 6 日公开更新版 Rust Trademark Policy 的草案和公共 feedback form。根据 Foundation 4 月 17 日的说明,这份草案与十天 consultation 是 Rust Foundation、Rust Project Directors、Trademark Working Group 以及具有开源政策经验的法律顾问共同完成的。因此,把它描述成 Foundation staff 独自制定并单方面强加给 Rust Project,并不符合官方记录。129

与此同时,参与者自己也承认程序存在问题。4 月 12 日,Project Directors 等参与者表示,更广泛的 Rust Project 没有被充分纳入流程,process 与 communication 本应做得更好。consultation 结束后,Foundation 同样就透明度不足致歉,并表示 initial draft 存在许多需要处理的有效批评。129 因此,Foundation 单方强推程序完全没有问题这两个说法都比证据更强。

官方资料也能确认 2023 年 4 月草案收到了大量公开批评与 feedback-form 回应。但这些回应者不是随机样本,feedback form 是对政策感兴趣的人自愿参与的 consultation 渠道。因此,不能据此证明“绝大多数 Rust 用户反对”,也不能估计反对比例。Foundation 在 2024 年公布的 feedback summary 所直接支持的较窄结论是:提交的意见反复关注无意误用的后果、法律措辞与清晰度,以及 blog、talk、crate 名称、merchandise、logo modification 等使用范围。130

8.6.2 不是“撤回”,而是长期 revision 后最终获批

2023 年 consultation 结束后,Foundation 并没有宣布草案生效,而是表示将共同审查 feedback、制作新 draft,并在 Foundation 与 Rust Project leadership 都满意之前不会实施任何政策。129 这项工作也没有很快结束。2023 年 Rust Leadership Council 把改善与 Foundation 的 interaction、明确 Project Directors 的角色列为优先事项;2024 年 6 月 Foundation board minutes 则记录 trademark work 因法律顾问 availability 而延迟。131

2024 年 11 月,Leadership Council 与 Foundation 再次公开 revised draft,征求 final feedback。根据 Foundation 的说明,基于 2023 年提交的意见,修改包括取消 package-name restriction,并使 logo 颜色修改、部分非商业 merchandise、event、publication 等规则更加宽松或清晰。130 这一版本仍是用于 final feedback 的 draft,而不是已经生效的最终政策。

2025 年 1 月 23 日,Rust Foundation 宣布包括 Project Directors 在内的 Foundation Board 已批准更新后的政策。当前 Rust Language Trademark Policy 明确说明 Foundation 拥有并保护 Rust 与 Cargo 的 trademarks/logos,同时另行说明 Rust programming-language project 由 Leadership Council govern。当前 policy 允许许多用途无需事先批准,例如准确说明 Rust compatibility、在 crate/repository 名称中使用 Rust、小型非营利 event、book、blog、publication;而对于暗示 official affiliation 的用法以及部分商业或 modified distribution,则需要 permission。132

8.6.3 不把 Foundation governance 与 Rust Project governance 视为同一件事

当前 Rust governance 文档把 Leadership Council 作为负责 Rust Project 整体成功与组织协调的 top-level body,而重大 technical decision 通过 RFC 与相关 Project team 的 deliberation 进行。相对地,Rust Foundation 是独立 nonprofit,承担 trademark、法律与行政、财务、infrastructure support 等 stewardship 责任。Project Directors 是 Rust Project 在 Foundation Board 中反映自身利益的制度渠道;当前说明也把他们描述为负责 Project 与 Foundation 关系的 elected group。131

因此,如果把商标争议中的 language feature decision、moderation 与 Foundation 的法律责任合并成同一个权力轴,就会误读组织结构。

问题 主要制度单元 本案例可以直接支持的范围
Rust/Cargo trademark 的所有、保护与使用许可 Rust Foundation 与 Foundation Board 法律 trademark stewardship 与最终 policy approval
Rust Project 的组织方向和 cross-team coordination Leadership Council Project-level governance 与 Foundation relationship 的协调
language、compiler、library 等 technical decision 各 Rust Project team 与 RFC process technical trade-off 与 consensus procedure;与 trademark policy 分离
在 Foundation Board 中代表 Project interests Project Directors 把 Project perspective 接入 Foundation-related decision 的制度通道
执行行为规范与调解冲突 Rust Project Moderation team Code of Conduct 与 community-standard 范畴;与 trademark ownership 分离

8.6.4 这场争议能够作为哪些 governance evidence

本案例强力支持的是:相关组织自己承认,不只是政策内容,政策形成程序也可能影响信任与可接受性,并据此修改了程序。 2023 年 Project 参与者与 Foundation 承认 communication 和 wider-project inclusion 不足;之后 Leadership Council 把明确 Foundation interaction 与 Project Director role 作为优先事项。2024 修订吸收了公开 feedback 中的具体 concern,2025 最终政策经过 Board approval。129130132

但更强的结论需要额外边界。feedback 的数量不能测量全部 Rust 用户的信任水平或反对比例;Crab-lang 等 protest fork discussion 的存在也不能单独估计真实 ecosystem fragmentation 风险的概率。承认程序问题也不能证明 Foundation 或 Project participant 有意扩大 community control 的心理或政治动机。

反过来,最终政策在 2025 年获批,也不意味着 2023 年的 criticism 没有根据。实际 revision 中,crate/package naming、logo modification、publication、merchandise、non-endorsement 等多项争点被修改或澄清。130 对 draft 的批评是否成立、revision process 是否改善、current policy 是否适当,是三个不同的评价对象。

中间结论

从 RQ5 看,2023 商标争议不是用来判断 Rust community 性格的案例,而是用来区分制度权力、公开 consultation、批评范围与 policy revision的案例。initial draft 不是已实施的 final policy,也不是 Foundation 单独的产物,但 wider Project involvement 与 communication 不足确实得到官方承认。后续流程经过 2024 revised draft 与 final feedback,并在 2025 年由 Foundation Board 批准;current policy 对当时争议的多个领域作出了不同或更明确的规定。

因此,更一般的教训也必须保持条件性:应区分持有法律资产的 Foundation、治理技术工作的 Project、把 Project 连接到 Foundation Board 的 Project Directors,以及 moderation 和 technical teams,并按时间区分 draft、feedback、adoption。这样才能避免把公开争议立即改写成单一的“Foundation 对 community”权力叙事,也避免因为后来形成 agreement 就抹去早期真实的程序问题。

8.7 政府建议与产业成功案例的引用范围

政府 guidance 与产业案例都可以提供强证据,但它们支持的是不同种类的命题。应当减少 memory-safety vulnerabilitymemory-safe language 是重要手段Rust 是其中之一Rust 最适合某个具体 projectRust 应当成为所有 system 的默认语言,并不是同一个主张。本节不估计 online discourse 中这些结论出现得有多频繁,而是分析把这些命题合并时还需要哪些额外前提。

8.7.1 NSA/CISA 的建议以多种 memory-safe language 和条件性 adoption 为前提

NSA 的 Software Memory Safety 最初发表于 2022 年,并在 2023 年 4 月更新为 Version 1.1。当前公开的 v1.1 建议,在可行时考虑从 C/C++、assembly 等 inherent memory protection 较少的语言战略性转向 memory-safe language。它把 Python、Java、C#、Go、Delphi/Object Pascal、Swift、Ruby、Rust、Ada 一并列为示例,同时说明不同 MSL 的保护程度并不相同,compiler option、analysis tool、OS configuration 等 hardening 仍然有价值。133

2025 年 NSA/CISA 联合发布的 Memory Safe Languages: Reducing Vulnerabilities in Modern Software Development 对这一边界说明得更具体。文档把 Ada、C#、Delphi/Object Pascal、Go、Java、Python、Ruby、Rust、Swift 作为示例,并指出 language choice 会随 concurrency、performance 等条件变化。它还明确说明 MSL adoption 并非在所有 circumstance 或 solution area 中都现实,大型 existing codebase 与 mission-critical system 可能面临显著迁移成本。134

尤其重要的是,2025 年联合 guidance 并不要求把 existing code 全部 rewrite。它讨论了利用 interoperability 进行 incremental integration,也讨论了在 MSL adoption 不现实的情况下如何 harden non-MSL code。134 因此,这些资料强力支持的是把 memory safety 提升为设计目标并积极评估 MSL adoption 的 policy/engineering direction,而不是“政府把 Rust 指定为唯一批准语言”的结论。

8.7.2 2024 ONCD 报告把 Rust 作为示例,同时也记录适用性边界

美国 Office of the National Cyber Director 2024 年的 Back to the Building Blocks 把 memory-safe language adoption 作为 secure-by-design 的 high-leverage measure。报告说明,新产品可以从一开始选择 MSL,existing codebase 则可以先迁移 risk 较高的 function 或 library,采用 hybrid approach。同一报告明确指出不存在 “one-size-fits-all solutions”,memory-safe language 也不能消除所有 cybersecurity risk。135

其中 space system 一节尤其能说明 Rust 引用的边界。报告描述一种需要 close-to-kernel control、deterministic timing,以及没有 garbage collector 或可以 override GC 的 edge case,并把 Rust 作为满足这三个特性的 memory-safe language 示例之一。但报告紧接着说明,当时 Rust 在 space system 中尚未得到充分 fielded proof,还需要进一步发展 toolchain、workforce education 与实际 case study;同时还把 memory-safe hardware 和 formal methods 作为 complementary approach。135

因此,“White House 已把 Rust 指定为 systems programming 标准”比报告本身更强。报告直接支持的是 memory safety 这一 security objective、MSL adoption 的高价值、Rust 作为某些 constrained native workload 的有前景示例,以及判断 applicability 时必须同时考虑 workload 与 maturity 的边界。

8.7.3 从政府建议走到“Rust 是唯一现实替代”需要单独比较

下面不是任何机构或个人的直接引语,而是为了检查把不同政府资料组合后可能形成的推论而写的合成命题

  1. 政府机构建议减少对 memory-unsafe language 的依赖并扩大 MSL adoption。
  2. Rust 是政府资料列出的 MSL 之一,DARPA 也在推进 C-to-Rust 自动翻译研究。
  3. 因此,在 systems programming 中 Rust 是唯一现实的替代方案。

前两个前提可以由文档支持,但第三个结论缺少 candidate comparison。NSA/CISA 列出的语言在 runtime model、deterministic behavior、FFI、platform coverage 和 ecosystem 上各不相同,而且列表中也包括 Ada 这类可支持 GC-free native execution 和 high-assurance domain 的其他候选。反过来,在某个具体 low-level workload 中,Rust 的 ecosystem、interoperability、performance 与 memory-safety model 的组合确实也可能最有优势。正确结论取决于project requirement 与 candidate-specific evidence,而不是是否出现在列表上

政府文档中的语言列表也不能当作 exhaustive standard。NSA 与 NSA/CISA 都以 “examples” 或 “such as” 的方式列出多种语言。133134 因此,未列出的语言不会自动变成 memory-unsafe 或被 policy 禁止;出现在列表上也不等于通过了某个特定 workload 的适用性认证。

要证明 project-level 的排他选择,至少需要比较 threat/defect model、latency 与 worst-case timing、memory/resource budget、GC/runtime 是否可接受、target/toolchain support、certification/assurance 要求、existing code 与 ABI、interoperability cost、staffing 和 multi-year lifecycle。如果其他现实候选都无法满足这些要求,Rust 可以成为该 project 事实上唯一的选择;但这个结论来自比较本身,而不是政府权威本身

4. 产业成功案例的因果归属与外部有效性

产业案例是证明技术选择有效的重要证据。但替换语言前后,数据结构、架构、并发模型、连接复用、部署方式、硬件、团队熟练度和观测指标也可能一同变化。要把全部成果归于语言本身,需要说明相同工作负载和基准、同时改变的因素、比较周期以及反事实替代方案。

  1. Android 的安全成果:Google 报告称,Android 内存安全漏洞占比从 2019 年的 76% 降至 2024 年的 24%,2025 年首次低于 20%。2025 年分析基于约 500 万行 Android Rust 代码中在发布前发现并修复的一项潜在漏洞,估计其内存安全漏洞密度比历史 C/C++ 数据低 1,000 倍以上。136 137 这证明 Rust 在 Android 新增和活跃开发代码以及高风险边界中取得强成果。但总体下降还受包括 Java、Kotlin 在内的内存安全语言策略、既有代码成熟、沙箱和防御层影响,不能把全部下降归于 Rust。
  2. Discord 延迟案例:Discord 报告称,把特定 Read States 服务从 Go 重写为 Rust 后,周期性延迟尖峰消失,延迟、CPU 和内存指标改善。原文说明了 Go 1.9.2 系列实现、巨大 LRU 缓存和每两分钟强制 GC 的具体条件,并明确不主张把所有系统重写成 Rust。原文也没有给出 P99 延迟降低 50% 的数字。138
  3. Pingora 的资源节省:Cloudflare 以相同流量比较旧 NGINX/OpenResty 服务,报告 Pingora 少用约 70% CPU 和 67% 内存。官方说明把原因同时归于 Rust 代码效率、多线程架构、消除 C–Lua 边界复制以及提高连接复用率。特别是延迟改善主要来自使用共享连接池的新架构,而不是代码执行速度。139 因此,这是“以 Rust 实现的重新设计”的成果,而不是只改变语言的受控实验。
  4. Firecracker 启动时间:AWS 公布的低于 125 毫秒启动时间,是在 i3.metal、默认 microVM 大小和最小设备模型条件下的 Firecracker 系统成果。AWS 的确因内存和线程安全选择 Rust,但这些数据没有把启动时间分离为 Rust 语言的独立性能效果。140
  5. Linux 内核的持续采用:2025 年 Linux Kernel Maintainers Summit 后,Miguel Ojeda 说明 Rust 支持实验结束,Rust 将继续保留。同一说明也指出,并非所有内核配置、架构和工具链组合都已完成,仍有大量工作和实验性组合。141 这证明 Rust 支持的持续性,但不意味着内核整体默认实现语言已转为 Rust。

5. 数字、漏洞与路线图的来源追踪

量化主张中的数字越大、越具体,越显得有说服力;但调查年份、总体、分母、漏洞描述和路线图状态变化时,结论也会变化。

  1. 生态规模:226.7 万开发者是 JetBrains 根据 2024 Developer Ecosystem 数据估计的过去十二个月 Rust 使用者数量。142 2025 State of Rust Survey 收集了 7,156 份回答,并明确警告不要从约 7,000 份回答过度外推整个社区。143 两项资料的测量目的和总体不同,不能作为同一共同统计引用。
  2. CVE 归属:CVE-2025-30388 的官方描述是 Windows Win32K-GRFX 堆缓冲区溢出,需要本地执行和用户交互。官方记录没有把代码归于 Rust,因此不能用它支持“Windows 内核 Rust 代码的首个远程代码执行漏洞”这一说法。144 相比之下,CVE-2025-68260 是 Linux Rust Binder 中对 unsafe 列表删除操作的并发访问造成数据竞争和指针损坏。145 该案例要求审计 unsafe 契约和共享状态,但既不支持“Safe Rust 的保证不存在”,也不支持“影响会自动限制在 unsafe 块内部”。
  3. 异步功能状态:Rust 项目的 2026 路线图说明当前仅有同步析构函数,并指出异步清理的需要,把实现保证析构和 async drop 的基础列为 2026—2027 年探索事项。146 这是探索方向,不是确认会包含在某个“2027 edition”中的承诺。

6. 区分 security guidance、Rust-specific research program 与“standard”宣言

2025 年 NSA/CISA 联合 guidance 强烈建议 MSL adoption,同时明确说明合适的语言与迁移方式取决于具体情况,complete rewrite 并非必需,而在 MSL adoption 不现实的地方仍需要 non-MSL hardening。134 因此,它是把 memory safety 置于优先位置的 security guidance,不是只指定 Rust 的 procurement standard 或 language mandate。

DARPA 的 TRACTOR 是范围更窄、真正 Rust-specific 的证据。该 program 的目标是研究如何把 legacy C 自动翻译成质量接近熟练 Rust developer 编写的 safe、idiomatic Rust。147 这直接说明 C-to-Rust translation 是美国 defense research 的具体投资对象。但 research-program goal 既不是“所有 C code 已经可以正确且经济地自动翻译”的 deployment result,也不是禁止其他 MSL 的 policy decision。

因此,当使用“已经成为标准”或“政府选择了它”这样的表述时,至少应区分三个层次:

  • Security objective 与 guidance: 多项美国政府资料一致支持减少 memory-safety vulnerability,并在现实可行的领域规划 MSL adoption。
  • 特定 research、procurement 或 project choice: TRACTOR 等 program 明确选择 Rust,但这一选择只在该 program 的 mission 与 evaluation criteria 范围内成立。
  • Universal language mandate: 当前引用的 guidance 并没有规定所有 software producer 必须使用 Rust,也没有规定所有非 Rust 选择都必须作为例外来证明。若要主张这种义务,需要另行给出具有适用范围的 statute、procurement rule、contract term 或 domain-specific standard。

产业成果也适用同一原则。Android、Pingora、Firecracker、Discord 与 Linux 可以证明各自环境中的 production feasibility 与 observed outcome,但把这些案例与政府 policy 放在一起,仍不会自动形成 universal Rust mandate。强烈的 memory-safety 政策方向、Rust 的重要实际成果,以及某个具体 project 采取 Rust-first 选择,可以同时为真;即便如此,整个 software domain 的语言选择仍然是独立的比较问题。

8.8 话语背后:官方改进努力与共同体治理

前几节分析了部分非官方话语中的夸张、排他性技术选择以及资格和地位判断。但这些案例不能被概括为 Rust Project 整体的态度。官方项目另有用于提出和审查语言、库、工具与治理问题的程序,这些程序与非官方在线话语属于不同的分析单位。

Rust 的 RFC(Request for Comments)流程为语言语义、标准库重大变更等实质性变化提供公开提案、设计审查、缺点与替代方案讨论以及相关团队决策的路径。正如 RFC 仓库所说明的,并非所有变更都需要 RFC,RFC 被合并也不会自动保证实现或最终稳定。因此,RFC 的存在证明的是 官方提案和审查路径确实存在,而不是证明所有批评都会被接受,也不能代表所有参与者的态度。118

Project Goals 和各团队的工作记录也显示同样的边界。2025-2026 年官方资料公开列出 async ergonomics、构建和编辑器性能、调试、低层项目支持、borrow checker 改进等尚未解决的问题,同时讨论团队支持、可用资源和实现难度。118 这说明项目承认未完成的任务,但 goal 文档并不等于已完成的成果;实际改进仍须通过实现状态和测量结果单独判断。

评估官方治理时至少应区分四层:1)问题是否被官方承认;2)RFC、project goal、issue、团队决定等正式路径是否存在并实际运作;3)提案是否完成实现并进入稳定发布;4)compile time、错误率、可用性、维护成本等目标指标是否在真实环境中改善。不能仅凭前一层的存在推断后一层;反过来,也不能因为仍有未完成任务就认定整个改进程序毫无意义。

这种区分也避免第8章变成单向批评。非官方空间中的防御性论证应作为论证本身接受评价,官方项目的改进活动则应依据官方记录和实际结果评价。二者可能相互影响,但没有依据把一方的案例当作另一方整体的代表性样本。

因此,第8章的结论是有边界的。围绕 Rust 的话语中可以观察到把条件性的工程优势扩大为普遍优越性或个人地位判断的论证;与此同时,Rust Project 也确实存在记录未解决问题并审查变更的制度机制。前者不会自动证明语言本身有缺陷,后者也不会自动证明技术成功或共同体文化健康。主张、程序、实现和测量结果必须分别在各自的证据层级上评价。


第5部:综合分析与结论

第5部综合前文已经审计的分析,但不增加新的强因果主张。第9章仅在现有证据支持的范围内回答五个研究问题,第10章则在此基础上讨论改进任务和技术选择框架。

9. 重新评价 Rust:效用、约束与技术选择策略

第9章的作用不是再次赞美或反驳 Rust,而是把第1-8章确认的保证边界、成本、工业案例、变更策略和话语问题合并成一个技术选择问题。

9.1 Rust 的技术特性与适用领域分析

Rust 最重要的工程优势之一,是在 Safe Rust 规则以及 sound 的底层抽象成立的范围内,把特定类型的内存错误和 data race 转化为编译期约束。use-after-free、无效引用生命周期以及 Safe Rust 引用规则所禁止的 aliasing pattern 因而可在执行前被阻断。对于同时要求低延迟、直接控制资源使用、native-code 性能和 memory safety 的组件,这构成了很强的选择理由。不过,实际 latency 与 resource bound 仍必须结合 allocator、同步、操作系统和 workload 另行测量或证明。

但保证边界必须明确。unsafe 实现的 soundness、FFI contract、library 和 OS interface 都带来额外义务;Safe Rust 也不会消除 logic error、deadlock、resource exhaustion、memory leak、错误的权限检查或 panic 导致的服务中断。把“能够编译”扩展为“程序是安全的”或“没有安全漏洞”超出了保证范围。

Android、Pingora、Firecracker、Discord 和 Linux 等案例说明 Rust 能在特定 production workload 中实际使用,一些案例还报告了 memory safety、去除 GC、资源使用、latency 或维护方面的收益。但 rewrite 往往同时伴随 architecture、algorithm、workload、hardware、deployment、testing 和 staffing 的变化,因此不能把全部结果归因于语言本身。

Rust 的适用性因此取决于 defect model 和运行条件。对于强调 memory safety 与 low-level control 的新系统组件、网络、存储、虚拟化和安全边界,它可能有较高优先级;而对于成熟 legacy 资产、hard real-time 或认证约束、丰富的既有平台生态、或者 GC 成本并不重要的业务应用,其他方案可能有更低的 lifecycle cost。更准确的问题不是“这是不是好语言”,而是“要减少哪些 failure,并愿意承担哪些 cost”。

9.2 技术生态现实与多维开发者能力模型

语言的技术价值与开发者个人价值不是同一个变量。Rust proficiency 对需要 Rust 的岗位当然重要,但没有依据把对某一语言的偏好或熟练程度当作一般智力、专业性或道德价值的代理指标。

software engineering 同时包含 requirements、design、implementation、testing、security、performance、operations、maintenance、collaboration 和 domain knowledge。招聘与能力评估应以实际岗位相关的 work sample 和 structured criteria 为中心。Rust 岗位可以直接评估 ownership、borrowing、async、FFI 和 ecosystem experience,但这些未必是其他岗位的核心标准。掌握一种较难语言,或不使用这种语言,都不足以解释整体工程能力。

市场资料与偏好资料也必须分开。调查中的 Rust satisfaction、特定企业的 adoption、真实 job-posting market size 对应不同群体和指标。把它们连接起来需要独立的 labor-market data 和明确的 sampling definition。因此,“语言受欢迎所以职业市场一定大”和“职位少所以技术价值低”都不能成立。

教育亦然。ownership 与 borrow checking 可以帮助形成关于 memory 和 aliasing 的重要思维方式,但不会替代 data structure、OS、network、concurrency、compiler、manual memory management 的全部基础学习。反过来,也没有证据证明必须亲自在 C/C++ 中经历 pointer bug 才能理解系统。更合理的做法是根据学习目标组合抽象层和低层经验。

9.3 技术共同体、组织评价与生态可持续性

生态可持续性并不只由语言设计决定。maintainer capacity、资金与时间、release/security response、documentation、onboarding、decision procedure 以及组织的长期投入能力都会发挥作用。第8章讨论的 RFC 与 project-goals 说明存在进行协调的制度机制,但机制本身并不保证良好结果。

在线话语也有相同的推理限制。一些讨论会用对方的资格、智力或道德判断取代技术反驳,或把 Rust 之外的选择定义为不负责任。这些材料可以用于分析论证结构,但在没有 sampling design 的情况下不能用于估计 Rust 用户整体的倾向或频率。反过来,官方 Code of Conduct 或 RFC process 的存在也不能证明所有真实互动都健康。

在组织层面,应同时考察 technology choice 和 evaluation system。预防性工作、testing、documentation、refactoring、observability 往往没有短期 feature output 那么显眼。如果评价过度依赖 lines of code、加班、紧急恢复等可见信号,成员就会有优化这些指标的激励。与把问题归因于个人智力或国籍相比,从 goal、incentive、authority/responsibility、resource allocation、psychological safety 和 labor-market condition 解释这些现象更容易检验。

第9章的综合结论因此是有边界的。Rust 是一种在 sound Safe Rust 边界内强力阻断特定 memory error 和 data race 的重要 systems-programming tool。来自多个实际工业环境的案例已经确认 Rust 的 production feasibility,部分案例还观察到与 Rust adoption 同时出现的条件性收益。同时,这些保证不会自动越过 unsafe、FFI、logic/resource/operational boundary,compile-time、tooling、learning、integration 和 transition cost 也确实存在。某些项目适合新 Rust 实现或 selective adoption,另一些项目则可能更适合 modernization、hardening、partial replacement 或继续使用既有语言。

因此,对五个研究问题的共同答案不是 language ranking,而是 明确边界的选择程序。先定义必须控制的 failure class,再比较候选技术的 guarantee 与 failure condition,同时计算既有资产、transition risk、operations、staffing 和 ecosystem cost。adoption case 应作为 feasibility 与条件的证据使用,而 causal effect 和 universal suitability 必须单独检验;技术偏好也不应被扩大为对个人地位的判断。在这些边界内,Rust 的优势已经足够强,没有必要把它改写成普遍命题。

10. 结论:生态可持续性的课题与展望

第10章的作用不是再增加一种技术优越性主张,而是把第1-9章已经审计的技术、产业与组织结论转换为条件明确的建议。这些建议优先考虑的价值包括:减少严重缺陷、性能与资源使用的可预测性、服务韧性、长期可维护性、变更的可逆性、供应链安全,以及决策依据的可追溯性。这里并不预设任何一种价值在所有场景下都必然压倒其他价值。

因此,本章不预测“Rust 是否会成为未来的主导语言”。相反,它依据前文已经确认的保证边界与实际成本,提出 Rust Project 与采用 Rust 的组织应当优先处理哪些问题,以及应使用什么证据来判断这些问题。

10.1 生态结构性改进的课题

结构性改进并不等于增加功能数量。在长期运行的系统中,互操作边界、保证文档、开发反馈延迟、供应链与维护能力,以及治理结果的可追溯性,都可能成为瓶颈。当前官方资料中能够确认的课题也横跨这些不同层面。

1. 互操作性与 ABI:把“没有稳定 ABI”分解为真正的问题

Rust Reference 明确指出,原生 extern "Rust" ABI 不提供 stability guarantee,而默认 repr(Rust) 也只提供 soundness 所需的有限布局保证。同时,Rust 支持 dylibcdylib 等动态链接产物,也提供 extern "C"repr(C) 等明确的互操作边界。102 因此,把问题概括为“Rust 不能 dynamic linking”并不准确。

真正的问题是:哪个边界必须作为兼容性契约维持,以及需要维持多久。在长期独立部署的 plugin、系统库、Rust/C/C++ 混合代码等重视 binary compatibility 的场景中,ABI、representation、allocator ownership、error 与 unwind、lifetime、version negotiation 都必须显式设计。相反,对于使用单一 toolchain 一同构建和部署的应用,Rust-native ABI 的长期稳定性可能并非最高优先级。

2026 Rust Project Goals 包含继续梳理 C++/Rust interoperability 问题空间的工作,相关官方资料也没有假定在短期内把大规模既有 C++ 资产全部重写既现实又合理。148 因此,与其把生态改进固定为单一的 libstd stable ABI 目标,不如把真实 migration 边界所需的互操作契约与工具拆分为可测量的问题。

2. 高保证领域:弥合语言保证与可验证 safety case 之间的距离

Safe Rust 提供强保证,但高保证系统必须能够追踪这些保证依赖于哪些 unsafe 实现、compiler、library、target 与 toolchain。Rust 的 2026 年官方目标包括:为 sound unsafe 模式提供规范性文档、持续维护 Formalized Language Specification、sanitizer 支持、MC/DC coverage,以及 Rust-for-Linux compiler 相关工作——这些都属于强化保证与验证基础设施的工作。149

尤其值得注意的是,官方 goal 文档本身记录了当前 unsafe 权威文档存在空白。这既不能推出 Rust 不适合高保证领域,也不能因为 goal 已经登记就认为问题已经解决。具有较高 assurance level 要求的项目,应把拟使用 compiler 与 library 的 qualification 状态、normative contract、coverage、static/dynamic analysis、traceability、长期支持范围,与实际认证和运行条件逐项对照。Ada/SPARK、C/C++ 的验证工具以及其他 memory-safe language 也应按同一组要求比较。

3. 构建、IDE 与调试成本:测量目标 workload 的 feedback loop,而不是给整个生态打一个等级

如第5章和第6章所示,2025 compiler-performance survey 同时存在对 build/editor latency 满意的回答和将其报告为严重 blocker 的回答。特别是 self-selected 样本,以及要求回答者选择“问题最大的项目”的问题,不能推广为所有 Rust workload 的平均体验。93 调试能力缺口也会因 debugger 与操作系统而不同。98

因此,与其给 Rust tooling 贴上“成熟”或“不成熟”的单一标签,不如在准备采用 Rust 的 repository 中实际测量 clean build、incremental build、CI queue、rust-analyzer latency 与 memory、link time、debugger 功能和 artifact size。如果这些成本违反真实的开发或运行目标,就应测试 compiler/Cargo/IDE 改进、dependency 结构调整、profile 与 linker 选择、build cache 等措施,再重新测量结果。官方 project goal 可以说明改进方向,但不能代替已经实现的效果测量。118

4. 供应链与维护:建立可运营的信任链,而不是用 crate 数量或版本号做代理指标

package ecosystem 的可持续性很难仅凭 crate 数量多少,或者 version 是否超过 1.0 来判断。对长期运行更直接的问题是:关键 dependency 由谁维护,release provenance 与 update path 是否可追踪,是否具备漏洞响应与 maintainer succession 能力,以及 registry 或分发基础设施故障时是否能够恢复。

Rust Foundation 将 ecosystem security 描述为持续变化的问题,并开展 audit、threat modeling 与安全工具开发。2026 Rust Project Goals 还包含 Rustup/Cargo 的可验证 mirroring prototype,以及稳定 Cargo SBOM precursor 的工作。150 这些事实既不说明当前供应链整体“不安全”,也不保证新工具能够解决所有风险。组织应根据自身 threat model 建立 dependency inventory、lock/update policy、provenance、SBOM、advisory response、private/official mirror policy、maintainer continuity 与 rollback procedure。

5. 治理:比公开计划更重要的是提高计划—实现—效果之间的连接性

如8.8节所示,RFC 与 Project Goals 是把问题和提案公开,并将其与团队审查及资源承诺连接起来的制度性机制。2026 goals process 同样明确描述了 bottom-up structure:contributor 提出 goal,相关 team 提供 champion 与 review support。118 这种结构可以提高改进的可能性,但 goal 的存在本身并不等于 completion、adoption 或 effect。

因此,可持续治理应能追踪问题公开 → 决策 → 实现/稳定化 → 实际观测到的效果。记录延期、中止的 goal 和不足的资源,与记录完成的 goal 一样,可以为未来的优先级判断提供信息。反过来,也不能把一两个 goal 的失败推广为整个项目的无能。正式流程的质量,比起文档是否存在,更应通过长期比较决策理由、资源分配、实现结果以及用户实际观察到的效果来评估。

这五类课题的优先级会因应用领域而不同。以 plugin ABI 为核心边界的产品,与单一 static binary appliance 的需求不同;safety-critical controller 与一般 web service 所需的 assurance case 也不同。因此,比“Rust ecosystem 要成熟就必须先解决 X”这种单一路线图更可验证的,是与目标 workload 的失败条件和 lifecycle 相联系的改进顺序

10.2 综合:同时处理技术、变更策略、能力、测量与组织环境的框架

必须区分第1-9章的经验性结论与本章的建议。经验性结论说明 Safe Rust 的保证边界、真实工业应用已经证明的可行性、build/tooling 与 migration cost、官方项目承认的未完成课题,以及实际观察到的话语范围。建议则是在这些事实之上选择优先价值的规范性判断。

本书的建议优先考虑以下价值:减少严重缺陷与 security risk;满足 performance 与 resource constraint;能够从 service interruption 与 change failure 中恢复;不无故丢弃已经验证的既有 asset;计入长期 maintenance、staffing 与 supply-chain cost;保留失败 transition 的可逆性;以及不把技术偏好转换为人的地位判断。如果项目优先的价值不同,其合理结论也可能不同。

在这些价值前提下,可以提出以下有条件的默认策略

场景 优先考察的策略 所依赖的价值与约束
新的 low-level、security-sensitive component 把 Rust 以及其他 memory-safe native language 作为强候选 降低 memory-safety defect 很重要,同时 GC/runtime constraint、performance/resource requirement 与 ecosystem fit 也必须成立
已稳定运行的大规模 C/C++ system 同时比较 hardening、modernization、新 Rust component、selective replacement 与 full rewrite 必须把 regression risk、implicit specification、ABI、rollback 与长期 coexistence cost 保留在决策中
safety/mission-critical system 比较实际 assurance evidence 与 toolchain,而不是比较语言名称 certification、normative contract、timing/resource bound、traceability 与长期支持必须满足所需 assurance level
可以接受 GC 与 managed runtime 的一般 application 不把 Rust 设为自动 default,同时比较 productivity、ecosystem 与 operation model 除 memory-safety guarantee 外,development speed、staffing、framework、fault isolation 与 operating cost 可能更具支配性
组织准备把新技术扩大到整体范围 在 bounded pilot 后根据测量结果决定是否扩大 必须分离 language effect 与 redesign effect,并确保 training、tooling、operation 与 supply-chain capacity 可持续

Android 的 new-code-first 与 interoperability strategy,以及 NSA/CISA 的 memory-safe language guidance,都表明条件式、渐进式方案是真实存在的选择,而不是只能在全面 rewrite 与单一语言 mandate 之间二选一。112 134 但这仍然不能证明 incremental migration 对所有项目都是最佳方案。

决策流程

  1. 定义问题与价值的优先级。 明确 latency、throughput、worst-case timing、memory、security、availability、certification、development speed、maintainability 中哪些是真正的 constraint。
  2. 测量 baseline 与 defect model。 记录当前 defect class、incident impact、repair time、build/CI feedback、performance、resource usage 与 operational burden。没有 baseline,就很难区分改进效果与 redesign effect。
  3. 用同一种格式写出候选技术的保证边界。 明确 Safe Rust、unsafe、FFI、GC、runtime、static analysis、formal proof 等候选机制分别保证什么、不保证什么。
  4. 把 change strategy 与 language choice 分开比较。 同时考虑继续维护、hardening、same-language refactoring/modernization、新 Rust component、selective replacement 与 full rewrite,并计入 specification recovery、interop、rollout 与 rollback cost。
  5. 在代表性 workload 上 pilot,并记录归因。 不只测 runtime performance,还测 defect discovery、build/IDE latency、memory 与 binary footprint、development time、incident、maintenance cost,同时记录 architecture、algorithm、hardware 与 staffing 的变化。
  6. 检查 lifecycle 与组织能力。 判断 dependency 与 supply-chain management、security response、maintainer continuity、toolchain support、hiring/training、dual-language operation、on-call load 与 knowledge concentration 在整个项目生命周期内是否可持续。
  7. 预先设定扩大与停止条件。 定义 target metric、rollout stage、observability、rollback boundary 与 failure budget,只有达到目标时才扩大范围。如果结果不好,应能停止、修改或回退,而不是为了维护 language identity 去重新解释失败。
  8. 记录会触发重新判断的证据。 compiler、ecosystem、standard、competing technology 与组织条件都会变化。把哪些 measurement 或 event 会改变当前结论写入 decision record,使技术选择保持为可证伪的假设。

这一流程把本书对 RQ3-RQ5 的最终建议具体化。对于 RQ3,工业 case 证明 feasibility 与条件性 outcome,但不是可归因于单一语言的普遍 effect size。对于 RQ4,maintenance、modernization、selective replacement 与 rewrite 不是等级序列,而是具有不同 risk profile 的策略。对于 RQ5,条件性的技术优势可以支持强烈的采用决定,但不能推出非使用者的智力、资格或道德价值。

Rust 的可持续性既不要求隐藏弱点,也不要求把弱点本身变成一种 identity。强保证应与精确边界一起说明;未完成工作应区分 plan 与 result;采用效果应通过 measurement 与 attribution 验证;失败的选择应保持可逆。在这些条件下,Rust 可以在某些领域被评价为非常强的工程选择,而在其他领域认为其他语言或 change strategy 更合理的结论,也应按同一证据标准被接受。


后记

本书一直追问到最后的问题,并不是“Rust 是好语言还是坏语言”。更准确的问题是:我们试图减少哪类失败,某项保障究竟成立到什么边界,为获得这种保障愿意承担怎样的成本与变更风险,以及出现什么证据时应当修正当前判断

第一,Rust 最强的工程价值在于:在 Safe Rust 契约成立、下层实现保持 sound 的范围内,特定类别的内存错误和 data race 会转化为由编译器强制执行的约束。这种保障既重要也实用。但它不会自动消除 unsafe 的证明义务、FFI 与外部契约、逻辑错误、deadlock、resource exhaustion、memory leak、错误的权限检查、panic 或运维故障。明确这些边界不是削弱 Rust 的价值,而是把其价值真正成立的范围说清楚。

第二,这种保障并不会把其他技术排列成一条单一的优劣序列。C/C++ 的 modernization 与 hardening、garbage-collected language 的 runtime model,以及 Ada/SPARK 的强契约和验证工具,分别具有不同的失败模型与成本结构。某个候选方案是否合适,取决于性能与 worst-case timing、资源上限、assurance 要求、既有资产与 ABI、ecosystem、staffing 和 lifecycle。因此,比较的目的不是选出冠军,而是找到所需保障与可承受成本的组合

第三,产业案例表明 Rust 可以用于真实的 production 环境,并且在特定条件下能够带来有意义的收益。但语言切换往往同时伴随 architecture、algorithm、hardware、deployment、testing 和组织能力的变化,因此不能把全部观测结果换算成语言本身的普遍因果效应。案例是关于可行性和适用条件的证据,而不是提前保证另一个项目会得到同样结果的证书。

第四,既有系统的变更策略也不是二选一。继续维护、hardening、同语言 refactoring 与 modernization、新增 Rust 组件、选择性替换高风险区域、全面 rewrite,都是具有不同风险的独立策略。好的决策来自把当前缺陷、隐含规格、回归风险、interoperability、rollout 与 rollback、长期运维成本放到同一标准下比较,而不是来自对既有投入的情感依附或对新技术的期待。

第五,技术选择不是给人排序的工具。Rust 熟练度在需要 Rust 的岗位上可以是重要能力,但它不是一般智力、整体软件工程能力或道德责任感的代理指标。本书分析的在线案例同样只是展示特定论证结构的质性材料,不是可以据此估计全部 Rust 用户特征或态度频率的代表性样本。正式项目治理与非正式话语也不应被当作同一个分析对象。

归根结底,Rust 的优势即使不被夸大也已经足够强。对一些项目而言,积极采用 Rust 可能是最合理的结论;对另一些项目而言,现代化既有系统、选择其他语言,或暂缓迁移反而可能更合理。关键在于,这个结论应来自明确的需求、可验证的证据,以及失败时可以回退的变更策略,并且能够随着新证据出现而被修正。

本书的目的不是终结技术争论,而是让我们能够更准确地说明一场争论究竟证明了什么、又尚未证明什么。把失败模型置于语言名称之前,把测量置于口号之前,把可验证的选择置于地位竞争之前——这就是本书最后提出的判断标准。


附录:技术讨论中观察到的论证谬误案例分析

本附录的目的不是评价某个社区或个人,而是练习识别技术讨论中可能遮蔽论证有效性的论证形式。下面的回应全部是为说明而构造的合成示例,不是现实帖文的直接引语,也不是对某位用户发言的重现、频率调查或代表性样本。因此,不能仅凭这些示例的存在推断 Rust 用户或其他技术共同体的整体倾向。

此外,识别出论证谬误,并不意味着对方的结论自动为假。结论可能为真,但给出的理由未必足以支持它。本附录在每个案例中区分:①真正需要检验的命题,②回应实际处理的命题,③缺失的连接前提或证据,④如何把问题改写为可检验形式。

案例 1:把技术批评转化为对发言者能力的判断——人身攻击

  • 语境: 某开发者认为 Rust async 带来了学习成本,或在特定代码库中增加了生产力成本。
  • 合成回应: “如果你觉得这个功能难,问题在你的能力,而不在语言。”
  • 分析: 发言者的经验水平可能影响使用体验的解释,但它本身不能反驳关于 API 复杂度、错误风险或开发时间的主张。技术命题被替换成了对人的评价。
  • 可检验的重构: 明确 workload、团队经验、实现时间、defect、latency 和维护成本,并与其他执行模型或旧实现比较。经验水平可以作为变量,但不能直接充当结论。

案例 2:反驳背景或动机,而不是反驳主张——发生学谬误与动机推断

  • 语境: 一位有 C++ 经验的开发者认为 borrow checker 在特定设计中要求额外重构。
  • 合成回应: “你把它叫作约束,只是因为你依恋 C++ 的习惯,并害怕新的范式。”
  • 分析: 既往经验可能影响偏好,但推测出的动机并不能证明 borrow checker 在该设计中究竟造成什么限制、又带来什么收益。主张内容被主张者的心理解释替代了。
  • 可检验的重构: 用代码或最小示例展示相关 ownership 与 aliasing 关系,然后比较 Rust 所要求的重构、由此获得的保障和实现成本。

案例 3:把有限批评改造成更强的主张——稻草人谬误

  • 语境: 某人认为 Rust 的错误处理在特定 API 设计中较繁琐,或不如其他语言方便。
  • 合成回应: “所以你的意思是 Rust 的错误处理完全没用?”
  • 分析: “在特定条件下有成本”和“整个功能都没用”是两个不同命题。攻击更强的命题,并没有解决原本的比较。
  • 可检验的重构: 保留原主张中的条件与比较对象,分析在相关 error model 下 Result、异常、panic 或其他策略各自的权衡。

案例 4:把重构与重写并成一个类别——范畴错误、虚假二分与完美方案谬误

  • 语境: 团队讨论如何减少旧有 C/C++ 系统中的缺陷。
  • 合成回应: “真正的重构就是用 Rust 重写,其他改进都没有意义。”
  • 分析: 同语言 refactoring、hardening、selective replacement 与 full rewrite 在变更范围和失败方式上并不相同。某个策略不能在语言层消除全部 memory-safety defect,并不意味着其部分降低缺陷或改善维护性的价值为零。
  • 可检验的重构: 在同一 decision record 中,按当前 defect 分布、测试与隐含规格、migration/rollback 风险、FFI/ABI、性能、人力和 lifecycle cost 比较多个变更策略。

案例 5:把 legacy 状态转化为道德属性——错误类比与价值判断跳跃

  • 语境: 团队需要决定维护、现代化还是替换一个较老的系统。
  • 合成回应: “Legacy 本身就是坏的,因此保留旧技术一定不理性。”
  • 分析: 系统年龄可能与停止支持、technical debt 或人员风险相关,但它不是独立的质量指标。反过来,仅凭过去投入也不足以证明应该继续保留系统。真正相关的是未来成本和风险。
  • 可检验的重构: 测量当前 defect rate、运行稳定性、供应链与支持状态、可修改性、替换成本、回归风险和未来维护成本,再比较维护、modernization、部分替换和全面替换。

案例 6:把语言熟练度等同于一般智力或总体能力——构念混淆

  • 语境: 讨论 Rust 岗位的招聘标准,或更一般地讨论开发者能力。
  • 合成回应: “能学好 Rust 的人更聪明,所以 Rust 熟练度应该成为评价开发者的核心标准。”
  • 分析: Rust 熟练度在 Rust 工作中可能直接相关,但它不会自动测量一般智力、需求分析、设计、调试、运维、协作或领域知识。学习者表现出的特征究竟由学习造成,还是 self-selection 的结果,也是另一个问题。
  • 可检验的重构: 先定义岗位真正需要的行为和结果。需要 Rust 的岗位直接评估 Rust 知识,其他能力则用独立的 work sample 与结构化标准测量。

案例 7:把组织问题转化为全体成员的本质属性——过度概括与单一原因论

  • 语境: 讨论过量工作、不公平评价、知识集中和离职等组织问题。
  • 合成回应: “有能力的人都会离开,只剩无能的人,所以行业问题可以用从业者能力低下来解释。”
  • 分析: 工作条件和评价结构会影响 retention 与 performance,这一假设可以检验。但从有限经历直接推断整个行业的 selection effect 以及成员智力,会跳过总体定义、替代解释和测量变量。
  • 可检验的重构: 收集离职率、workload、薪酬、评价标准、incident burden、team tenure、bus factor、招聘和绩效数据,并把组织条件与个人能力作为不同变量分析。

案例 8:把所有反对意见都吸收到原有信念中——自我封闭论证

  • 语境: 对 Rust 的优势或采用必要性存在分歧。
  • 合成回应: “赞同的人理解这项技术;反对的人要么不懂,要么有自卑感。”
  • 分析: 如果赞同和反对都能成为同一结论的证据,就没有任何观察能够削弱这一主张。反证条件消失,只剩下对对方动机的猜测。
  • 可检验的重构: 预先写明哪些 benchmark、defect data、migration cost 或 ecosystem 变化会改变当前判断。针对这些条件和证据评价异议,并与对发言者心理的推测分开。

案例 9:把易观察的代理指标等同于群体属性——代理指标误用与样本泛化

  • 语境: 某组织奖励加班、代码量或显眼的紧急故障恢复。
  • 合成回应: “既然存在这种评价习惯,那么某个国家的开发者总体技术水平和智力都较低。”
  • 分析: 批评代码量或加班不是质量充分条件,是一个命题;判断一个国家群体的能力,是另一个命题。少数公司或网络案例既不是代表性样本,也不提供国家层因果解释所需的比较变量。
  • 可检验的重构: 在组织层面评估预防、重复事故、change failure rate、review quality、maintainability 与实际工作结果。如果确实需要群体比较,应另行定义总体与样本,并设计岗位构成、教育、产业结构等混杂变量。

案例 10:把多个成功案例合并成一个普遍标准——归因混合与泛化范围扩张

  • 语境: 讨论把 Android、网络服务、云基础设施、Linux、政府对 memory-safe language 的建议等不同性质的 Rust 相关证据放在一起。
  • 合成回应: “所有证据都指向同一方向,因此在任何系统中,不选择 Rust 的一方现在都应该证明自己是例外。”
  • 分析: 多个独立案例可以有力支持 Rust 的可行性和某些特定优势。但不同 workload、指标和分母不能合成单一 effect size;rewrite 同时改变的 architecture、algorithm、hardware 与运维也必须分离。建议采用 memory-safe language 的政策,与强制只使用 Rust 也是不同命题。
  • 可检验的重构: 分别标记每个案例支持的是可行性、某一组织的观测结果、因果效果,还是普遍适用性。随后按相同标准比较目标项目的 defect model、assurance、runtime/resource 约束、既有资产、migration risk 与现实候选技术。

如何使用本附录

在技术讨论中,与其尽快给论证贴上谬误标签,不如依次检查下面的问题。

  1. 对方实际提出的命题是什么,其条件与范围到哪里?
  2. 回应是否直接处理该命题,还是把它替换成更强或不同的命题?
  3. 从前提到结论所需的连接前提和证据是否明确?
  4. case study、survey、benchmark 或 policy document 是否真的支持代表性、因果性或普遍性?
  5. 出现什么观察结果时,当前判断应当被修改?

这套程序应当同样用于支持和批评 Rust 的论证。好的技术讨论不是给参与者的资格或身份排序,而是让主张范围、保障边界、可比较证据与反证条件变得更精确。


  1. 一种由运行时跟踪对象可达性等状态,并自动回收不再使用的内存的内存管理技术。 

  2. Rust Core Team, Laying the foundation for Rust’s future; Aaron Turon, Abstraction without overhead: traits in Rust。前者说明 Rust 作为 Mozilla Research 项目起步并转为独立项目的历史,后者说明内存安全、数据竞争防止与抽象成本这几个设计轴。 

  3. The Rust Reference, Behavior considered undefinedBehavior not considered unsafe; The Rustonomicon, How Safe and Unsafe Interact。官方文档也明确指出 unsafe 契约的健全性责任、语义规则尚不完整,以及死锁、资源泄漏和逻辑错误与内存不安全之间的区别。  2

  4. Aaron Turon, Abstraction without overhead: traits in Rust。该文把零成本抽象说明为 Rust 设计的核心原则,但并不普遍保证某个特定程序的性能结果。 

  5. The Rustonomicon, Data Races and Race Conditions; The Rust Programming Language, Using Threads to Run Code Simultaneously。官方文档区分 Safe Rust 对数据竞争的防止,以及一般竞态条件与死锁属于不同问题。 

  6. The Rust Programming Language, Understanding OwnershipReferences and BorrowingValidating References with Lifetimes。官方文档区分所有权、访问权限与引用有效性的作用,并说明生命周期标注不会改变引用实际存活的时间。  2 3

  7. Rust Project Goals, Stabilize and model Polonius AlphaThe Borrow Checker Within。2026 年官方目标说明,将使当前 NLL 分析拒绝的条件借用与 lending iterator 得到接受,而需要完全流敏感性的一些模式仍留作后续工作。 

  8. The Rust Programming Language, Rc<T>, the Reference-Counted Smart PointerRefCell<T> and the Interior Mutability PatternReference Cycles Can Leak MemoryShared-State Concurrency。这些文档说明运行时借用检查、引用计数、循环泄漏、原子引用计数的性能成本、锁以及死锁可能性。 

  9. Standard C++ Foundation, What is the zero-overhead principle?; Aaron Turon, Abstraction without overhead: traits in Rust。两份资料分别把该原则说明为 C++ 的设计原则以及 Rust 所继承的抽象目标,但并不规定特定程序的普遍性能结果。  2

  10. Rust Compiler Development Guide, Monomorphization; The Cargo Book, Profiles; The rustc book, Codegen Options; Richard Uhlig et al., Instruction Fetching: Coping with Code Bloat。这些资料说明单态化的编译时间与二进制体积成本、优化与代码生成单元及 LTO 的权衡,以及代码规模可能对指令获取造成的影响。  2 3

  11. The Rust Reference, Trait object types; Rust 标准库关键字文档,dyn; Rust 标准库,Box<T>Vec<T>String; The Rust Reference, Panic。这些文档分别区分 trait object 的运行时分派、堆分配与重新分配,以及越界索引触发的 panic。  2

  12. The Rust Programming Language, Performance in Loops vs. Iterators。官方示例只观察到一个工作负载中的相近性能,并明确指出更全面的比较需要不同的输入与条件。 

  13. The Rust Programming Language, Defining an EnumRecoverable Errors with Result; Rust 标准库,OptionResult; The Rust Reference, Pointer types。官方文档区分了 OptionResult 的状态表达、未使用 Resultmust_use 警告,以及非空引用和可为空原始指针之间的边界。  2 3

  14. The Rust Reference, match expressions, Patterns, The non_exhaustive attribute。这些文档说明模式守卫的条件行为、穷尽性检查、通配符以及外部非穷尽类型的 API 演进规则。 

  15. The Rust Reference, Behavior considered undefined。官方参考把构造无效枚举判别值、引用和类型值归类为未定义行为,并说明实现者必须在 unsafe 与 FFI 边界保持有效性前提。 

  16. The Rust Reference, Type layoutPanic; Rust 标准库,Option representationOption::unwrapResult::unwrap。这些资料区分默认枚举布局的有限保证、特定类型的空指针优化,以及 unwrap 系列的 panic 行为与 panic 策略。  2

  17. The Cargo Book, Why Cargo Existscargo。官方文档把 Cargo 定义为 Rust 的包管理器兼构建工具,并说明它通过统一命令体系提供依赖下载、构建、检查、测试、文档生成、打包与发布的范围。 

  18. The Cargo Book, Dependency Resolution, Features, FAQ — Why have Cargo.lock in version control?, SemVer Compatibility, Rust Versioncargo。这些文档区分了锁文件确定性的范围、离线解析差异、重复版本、feature 统一、SemVer 前提,以及 rust-version/MSRV 的边界。  2 3 4 5

  19. The Cargo Book, Build ScriptsSpecifying Dependencies; The Rust Reference, Procedural macros。官方文档说明 build.rs 的执行、原生库链接、目标特定依赖与构建依赖,以及过程宏在编译时执行、访问文件等安全边界。  2 3 4

  20. The Cargo Book, Registry Index, Publishing on crates.io, cargo ownerThe Manifest Format。这些资料说明 .crate 文件的 SHA-256 校验和、已发布版本的永久保留与 yank、所有权管理,以及许可证元数据的范围。  2

  21. The Cargo Book, Cargo Homecargo vendor; RustSec, cargo auditRustSec Advisory Database; CMake, cmake(1); Meson, Overview; Microsoft, vcpkg overview; Conan, Conan 2 documentation。这些资料支持有关缓存、vendoring、漏洞审计工具,以及 C/C++ 生态系统确实存在构建与包管理工具这一比较边界。  2 3

  22. The Rust Programming Language, What Is Ownership?, References and BorrowingReference Cycles Can Leak Memory; The Rust Reference, Behavior considered undefined; The Rustonomicon, Data Races and Race Conditions。这些资料区分了不依赖 GC 的所有权式内存管理、数据竞争与未定义行为的边界,以及一般竞争条件和内存泄漏仍位于保证范围之外这一事实。  2

  23. C++ Core Guidelines, C++ Core Guidelines。该指南说明现代 C++ 中包括 RAII 与资源句柄、通过智能指针和容器进行自动资源管理,以及减少原始所有权指针和直接 new/delete 使用等安全实践。引用这一资料是为了避免作出“C++ 不存在更安全的资源管理技术”这样的比较,并不意味着这些指南建议提供与 Rust 编译器强制检查相同的保证。 

  24. Oracle Java SE, Garbage Collector ImplementationAvailable Collectors。官方文档把垃圾收集的吞吐量与延迟作为不同指标,并说明不同收集器在暂停时间、吞吐量、内存使用及适用条件方面存在不同权衡。 

  25. The Cargo Book, Why Cargo Existscargo; The rustup book, Components, ProfilesOverrides; The Rust Programming Language, Useful Development Tools。这些资料说明 Cargo 的共同工作流程、rustup 的 toolchain/component 管理、默认 profile 中的 rustfmt 与 Clippy、可安装的 rust-analyzer,以及通过 rust-toolchain.toml 指定项目 toolchain 的范围。 

  26. Rust Compiler Performance Working Group, Rust compiler performance survey 2025 results; Rust Survey Team, 2025 State of Rust Survey Results。前者基于 3,700 多份回答报告 Cargo 命令使用情况以及构建、CI 等待成本,后者基于 7,156 份完整回答讨论限制生产力的问题。两项调查的资料都来自自愿参与的 Rust 相关受访者,因此不把它们用作与其他语言的受控比较,也不直接据此估计 Cargo 的因果效果。 

  27. CMake, cmake(1)CMake Presets; Meson, Overview; Microsoft, vcpkg overviewManifest mode; Conan, Introduction。这些资料表明,C/C++ 生态系统中同样存在实际的构建、测试、打包工具,以及基于 manifest 的依赖与版本管理、二进制包和私有仓库支持。 

  28. The rustup book, Cross-compilation; The Rust Programming Language, Installation。官方文档说明,即使 rustup target add 提供了目标标准库,仍可能另外需要外部 linker 或 SDK;普通 Rust 构建也需要 linker,而某些 crate 可能需要 C 编译器。 

  29. Maxwell E. McCombs and Donald L. Shaw, The Agenda-Setting Function of Mass Media, Public Opinion Quarterly 36(2), 1972, pp. 176-187。原研究把 1968 年美国总统选举期间 Chapel Hill 选民调查与他们使用媒体的内容分析进行比较,考察媒体对议题的强调程度与受众对议题重要性的认知之间的关系。因此,本书把“议程设置”应用于 Rust 话语时,需要提供可比较的话语资料、明确的时间范围、受众重要性测量以及因果推断限制,而不能只依据某些表达的重复出现。  2 3 4

  30. Rust Core Team, Announcing Rust 1.0 Alpha; The Rust Programming Language, Fearless Concurrency; Rust Core Team, A new look for rust-lang.org; Rust Project, Rust Programming Language。这些资料展示了安全性、性能与并发等早期价值主张、“fearless concurrency”这一官方表达、2018 年网站信息与口号的改版,以及本书修订时首页的 Performance、Reliability、Productivity 结构。它们记录的是官方信息的内容及其变化,而不是受众效果或整个社区话语的出现频率。  2 3

  31. Rust Core Team, Laying the foundation for Rust’s futureNext steps for the Foundation Conversation; Rust Foundation, Hello World!; Rust Project, Governance。2020 年资料说明 Mozilla 的资金与法律支持、成立基金会的目的,以及维持大多数 Rust 团队决策权限的边界;2021 年成立资料记录了当时的创始成员和董事会构成。Governance 页面展示了本书修订时 Rust 项目另行存在的治理结构。这些资料用于确认制度支持与结构,并不是对外部信任或采用效果的独立测量。  2 3 4

  32. Rust Project, Code of conductLearn Rust; The Rust Programming Language, The Rust Programming Language。行为准则说明适用于官方 Rust 空间的行为标准与 moderation 程序,学习页面与 Book 则展示官方学习资源的存在与范围。不能仅凭这些资源存在,就认为整个社区的行为、进入门槛降低、学习成果或贡献者留存效果已经得到测量。 

  33. The Rust Reference, Influences; The Rust Programming Language, What Is Ownership?References and Borrowing; C++ Core Guidelines, C++ Core Guidelines。Rust Reference 把 C++ 的 references、RAII、smart pointers、move semantics 列为直接影响,并把 ML Kit 与 Cyclone 的 region-based memory management 另列为影响来源。Rust Book 说明 scope 结束时通过 drop 释放资源的模式与 C++ RAII 的关系,C++ Core Guidelines 则定义通过 RAII 与 resource handle 进行自动资源管理。这些资料用于确认历史影响和各技术中规则的强制位置,并不用于把“ownership”这一一般概念的最早发明归属于某种特定语言。  2 3 4 5

  34. Ada Resource Association, Ada 83 Rationale, LRM, & Guides; Ada Reference Manual, Introduction; Ada 95 Rationale, Part Two, Chapter 3; Altran Praxis/AdaCore, SPARK - The SPADE Ada Kernel; SPARK User’s Guide, Applying SPARK in Practice; AdaCore, Programming Languages for Space Software。Ada 资料记录了 1983 标准、原始的可靠性、可维护性与效率目标,以及类型、subtype 的运行时检查传统;较早的 SPARK 文档记录最初的 SPARK 基于 Ada 83。当前 SPARK 资料说明 AoRTE 与 contract proof 的范围和假设,AdaCore 当前的概述则明确指出,后来加入的 SPARK pointer support 基于 Rust ownership model。因此,本脚注用 Ada/SPARK 区分历史比较与验证范围,而不是把它视为 Rust ownership 的直接祖先。  2

  35. The Rust Reference, Influences; Rust standard library, OptionResult; OCaml, Options。Rust Reference 明确指出的是 SML/OCaml 的 algebraic data types、pattern matching、type inference 对 Rust 的影响。Rust 与 OCaml 的官方资料分别展示了 Option/Resultoption 的 variant 结构,但仅凭这些资料,不能进一步确认 Rust 的具体错误处理 API 或整个单子式错误处理存在直接谱系。  2

  36. The Rust Reference, Behavior considered undefined。该文档把 data race、通过 dangling 或 misaligned pointer 进行访问、违反 aliasing、使用错误 ABI 调用、创建 invalid value 等列为 UB 示例,并规定即使在 unsafe 内部,UB 本身也不是被允许的行为。它还以 safe code 与 unsafe 实现交互时 safe client 不能引发 UB 为边界来说明 soundness。  2

  37. The Rust Reference, Array and array index expressionsThe unsafe keyword。普通数组与 slice 索引在无法静态确定时执行运行时边界检查,失败时 panic;而 get_uncheckedunsafe 函数要求 caller 满足“index 位于范围内”这一额外 safety condition。 

  38. The Rust Reference, The unsafe keywordBehavior considered undefined。Reference 说明 unsafe fnunsafe trait 等可以定义额外 safety condition,而 unsafe block、unsafe impl 等表示满足这些条件的 proof obligation。它同时把“safe client 不能通过 unsafe 代码引发 UB”作为 sound 的定义边界。  2

  39. The Rust Reference, External blocksApplication binary interface。External block 是 foreign item 声明的边界,Rust 2024 Edition 要求使用 unsafe extern。ABI 包括 "C""system""C-unwind" 等多种形式;ABI 和 signature 是否与真实外部代码契约一致,是该边界需要单独验证的责任。  2

  40. Cargo Reference, Profiles: panic; Rust standard library, std::panic::catch_unwindUnwindSafeJoinHandle::join; The Rust Reference, Destructors。这些资料说明 unwind 与 abort 策略的差异、catch_unwind 只捕获 unwinding panic 的限制、通过 join 观察 thread panic 的范围,以及 soundness 不能依赖 destructor 必然执行这一边界。  2 3

  41. The Rust Reference, Behavior not considered unsafe; Rust standard library, std::mem::forget; The Rust Programming Language, Reference Cycles Can Leak Memory。这些资料明确区分 leak、destructor 不执行与 Rust 的 unsafe 范畴,并说明 Safe Rust 中仍可能通过 reference cycle 或 mem::forget 等机制发生资源泄漏。  2 3

  42. The Rust Reference, Behavior not considered unsafe; Cargo Reference, Profiles: overflow-checks。Reference 把 deadlock、memory/resource leak、在不运行 destructor 的情况下终止等行为与 unsafe 区分开来。它还说明启用 debug_assert! 时 overflow 检查必须 panic,其他 build 则可以 panic 或采用有定义的 two’s-complement wrapping;Cargo profile 通过 overflow-checks 设置控制运行时 overflow 检查。  2

  43. The Rustonomicon, Data Races and Race Conditions。该文档把 data race 归类为 UB,同时明确指出 Safe Rust 并不防止一般 race condition。 

  44. Rust Security Response WG, Security advisory for the standard library (CVE-2024-24576)Security advisory for the standard library (CVE-2024-43402)。第一份 advisory 记录 Windows batch file 执行中 Command argument escaping 不充分的条件,以及 Rust 1.77.2 的修复;第二份记录特定条件下对该缓解措施的绕过及 Rust 1.81.0 的补充修复。这两项案例只用于有限地说明 safe API 的逻辑与安全 contract 不同于 memory safety,而不是用于衡量 memory-safety 缺陷的频率。  2

  45. Martin Fowler,Definition Of Refactoring,2004。Fowler 把 refactoring 定义为在不改变可观察行为的情况下改变内部结构。这里用该定义区分语言替换、新实现与狭义 refactoring。  2

  46. C++ Core Guidelines project,C++ Core Guidelines;LLVM/Clang,Clang-TidyAddressSanitizerThreadSanitizerUndefinedBehaviorSanitizer。Core Guidelines 说明现代 C++ 的资源、memory 与 concurrency 规则及渐进采用方式,Clang 文档则说明各分析与 sanitizer 的诊断范围和插桩成本。AddressSanitizer 与 ThreadSanitizer 文档分别明确说明其 runtime 并非设计用于链接到 production executable,也不是按安全敏感约束开发的。这些资料用于避免把工具检测与语言级保证、测试插桩与 production 部署混为一谈。  2 3

  47. Android Open Source Project,Memory safety,updated 2026-07-16;Google Security Blog,Rust in the Android platform,2021;Google Security Blog,Safer with Google: Advancing Memory Safety,2024。Android 对新 native code 使用 memory-safe language,同时继续对既有 C/C++ 采用检测、加固、sandbox 与 hardware mitigation。这里把它作为证明混合策略可行的特定大型平台案例,而不是所有代码库的最优策略证据。  2 3

  48. Martin Fowler,Strangler Fig,2024 update。该文讨论重要既有系统替换时发现详细规范的困难,以及大规模 cut-over 的风险,并把渐进 replacement 作为设计 pattern。这里用它定义一种变更策略选项,而不是作为“渐进迁移普遍比全面重写成本更低或质量更高”的总体统计证据。 

  49. Google Security Blog,Rust/C++ interop in the Android Platform,2021;Google Security Blog,Deploying Rust in Existing Firmware Codebases,2024。前者在 Android 中不假定全面 C++ 重写,而把互操作作为实际要求进行分析;后者说明优先处理新代码和高风险代码的渐进 Rust 采用,以及通过 shim 保留 C API 的方式。前者明确把分析范围限定在 Android platform,因此将两种策略推广到其他代码库时需要额外证据。 

  50. Google Security Blog,Bare-metal Rust in Android,2023。Android 团队记录了用 Rust 重写 AVF protected-VM firmware。这里把它作为特定安全边界选择 bounded rewrite 的有限案例,而不是为全面重写 Android 或一般大型 legacy system 提供正当性证据。 

  51. AdaCore,SPARK User’s Guide 27.0w — Levels of Software AssuranceProve Absence of Run-Time Errors。文档把 Stone、Bronze、Silver、Gold、Platinum 区分为不同 verification objective,明确说明 Silver AoRTE 不分析 Storage_Error,并说明 Platinum 只有在 contract 足以覆盖 functional requirement 时才成立。  2 3

  52. Ada Resource Association,Ada 2022 Reference Manual,尤其是 11.5 Suppressing Checks11.4 Exception Handling9 Tasks and SynchronizationC.6 Shared Variable Control13.9.1 Data Validity。Ada 2022 Reference Manual 对应 ISO/IEC 8652:2023(E)。这些资料用于区分 language-defined check 失败与 exception semantics、check suppression 所产生的 erroneous-execution 边界,以及 atomic/protected synchronization 与 unchecked access 的局限。  2 3 4

  53. AdaCore,SPARK User’s Guide 27.0w — Managing AssumptionsHow to Write Subprogram Contracts。GNATprove 结果可能依赖 modular contract,以及关于未分析 code 或 external environment 的 assumption;文档要求通过 testing、manual analysis、review 或其他合适证据另行论证这些 assumption。  2 3

  54. AdaCore,SPARK User’s Guide 27.0w — Concurrency and Ravenscar Profile。该文档通过限制 tasking 来避免 shared data 的 erroneous concurrent access,也就是 data race;同时其 atomic read-modify-write 示例明确表明,在没有 data race 的情况下仍可能出现 lost-update race condition。文档还说明,Ravenscar 单核 protected-object locking 使用 Priority Ceiling Protocol 来保证 deadlock 不发生,GNATprove 会检查 potentially blocking action 与多项 tasking 限制。同时,文档也记录了当前 project-wide tasking analysis 的实现范围限制:它依赖当前处理 source file 的 with closure,因此在某些彼此分离的 library/task 配置中可能漏掉相关检查。由此不能把已文档化的 data-race/deadlock 保证扩展成一般 concurrency correctness,也不能扩展到分析 context 之外的 whole-system 保证。  2

  55. Microsoft, Fundamentals of garbage collectionDebug a memory leak;Go Project, A Guide to the Go Garbage Collectorruntime.AddCleanup。Microsoft 资料说明 managed reachability、retained-object leak 以及 unmanaged resource 的显式 Dispose 路径;Go 资料说明基于 reachability 的回收,以及 cleanup 可能任意延迟或根本不执行的边界。因此,本节不把 GC-managed memory reclamation 扩大解释为 deterministic resource-release contract。  2

  56. Go Project, Go 1.26 Release NotesA Guide to the Go Garbage Collector;Oracle, Java SE 26 HotSpot VM Garbage Collection Tuning Guide — Available CollectorsGarbage-First (G1) Garbage CollectorErgonomics;Microsoft, .NET GC latency modes。Go GC guide 明确指出 implementation detail 可能随版本变化,Go 1.26 release note 则记录 Green Tea 已成为当前默认 collector。本节使用文档化的 cost/latency 范畴和 collector-specific trade-off,而不是旧的固定 pause 数字;并与 Oracle、Microsoft 资料一起用于区分 pause-time goal 与 hard deadline。  2 3 4

  57. Oracle, Java SE 26 G1 Garbage CollectorErgonomics;Microsoft, .NET GC latency modes;Go Project, A Guide to the Go Garbage Collector — Latency。三份资料分别展示 pause-time goal 的概率性/heuristic 性质、low-latency mode 的 memory-pressure 边界,以及 concurrent GC 中仍然存在的 latency source。本节不把这些内容扩大解释为 application-level hard real-time 保证。 

  58. 公开话语的定性案例包括 Reddit r/rust 的 backend/Rust 经验讨论unsafe soundness bug 讨论 以及 Rust Users Forum 的 长时间运行服务与 memory leak 讨论。这些案例仅用于展示论证的存在与结构;由于没有样本设计,不用于估计 Rust 社区整体的频率、代表性或共识。  2 3 4 5 6 7 8 9 10 11 12

  59. Rust Project, 官方网站 — Why Rust?rust-lang/rust README — Why Rust?。当前官方网站与仓库介绍把 Rust 描述为让所有人都能构建 reliable and efficient software 的工具,并把 performance、reliability、productivity 作为彼此独立的价值主张。这里不把这些内容扩大为概念优先权或普遍优越性的主张。 

  60. Rust Project, The unsafe keywordBehavior considered undefinedBehavior not considered unsafestd::mem::forget。Reference 把 unsafe 描述为 proof obligation 的创建与解除(create or discharge),并把 safe client 能够引发 UB 的 unsafe abstraction 定义为 unsound。它也不把 leak 或 destructor 未执行视为 unsafe,而 mem::forget 正因为这一保证边界而属于 safe API。  2 3

  61. ISO/IEC JTC1/SC22/WG21, N1128 — auto_ptr proposal wording, 1997, N4168 — Removing auto_ptr, N3245 — C++ Standard Library Active Issues List, 2011, N3296 — C++ FCD Comment Status. N1128 记录了 C++11 之前的 auto_ptr 及其 strict-ownership transfer semantics;N4168 记录了 2007 年接受 N1856 方向、加入 unique_ptr 并弃用 auto_ptr 的过程;2011 年的委员会资料显示 unique_ptrshared_ptr 已进入 C++11 时代的标准库设计。这些资料用于确认年代和标准化背景,不用于证明从某个特定 C++ smart pointer 到 Rust 的因果谱系。 

  62. C++ Core Guidelines, Resource management; ISO/IEC JTC1/SC22/WG21, N3025 — Specifying Pointer-Like Requirements; The Rust Programming Language, What Is Ownership?; Rust standard library, std::rc::Rcstd::sync::Arc。这些资料支持对 exclusive ownership、move semantics、moved-from unique_ptr state、RAII 与 reference-counted shared ownership 的语义比较;不把它们作为 unique_ptrshared_ptr 是某个 Rust 类型、或 Rust ownership 整体的一对一历史祖先的证据。  2

  63. The Rust Programming Language, What Is Ownership?, References and Borrowing, Unsafe Rust; The Rust Reference, The unsafe keyword, Behavior considered undefined。这些资料用于确认 compiler-checked ownership/borrowing rule、unsafe 仅允许的有限 operation、unsafe code 中普通检查仍然有效,以及 compiler verification 之外留下的 proof/soundness obligation。Rust Reference 还明确指出,此类 proof obligation 可以通过 run-time check 或 data-structure invariant 等方式 discharge,因此本节不把这个词用作 machine-checked formal proof 的证据。  2 3

  64. The Rust Reference, The unsafe keyword; The Rust Programming Language, Unsafe Rust, RefCell<T> and the Interior Mutability Pattern; The Rustonomicon, Splitting Borrows; Rust standard library, RefCell, Result::unwrap。Rust 文档在这一语境中明确把 type system 描述为保守近似,展示了用 unsafe implementation 建立 borrow checker 无法直接推断的 disjointness、再对外提供 safe abstraction 的做法;同时记录 RefCell 的 run-time borrow checking,区分会 panic 的 borrow/borrow_mut 与不 panic、返回错误的 try_borrow/try_borrow_mut,并说明 unwrap()Err 时 panic。这些资料并不能建立关于 developer psychology 或 defensive-programming behavior 的因果主张。  2 3

  65. C++ Core Guidelines, I.11: Never transfer ownership by a raw pointer or reference, R.20: Use unique_ptr or shared_ptr to represent ownership, R.32: Take a unique_ptr<widget> parameter to express that a function assumes ownership。Guidelines 描述了渐进采用以及 language/library semantics 与 tool-enforced guidance 的混合,也指出 unique_ptr parameter 会同时记录并 enforce ownership transfer。本节用这些资料比较 enforcement scope,而不是主张 C++ 与 Rust 提供等价的默认 memory-safety guarantee。  2

  66. Rust standard library, std::collections::LinkedListlinked_list module; The Rust Programming Language, Reference Cycles Can Leak Memory。标准库文档记录了具有 owned node 的 safe doubly linked list,并指出 VecVecDeque 通常更快、更节省内存且 cache locality 更好。Rust Book 记录 strong Rc cycle 可以造成 memory leak,Weak 不表达 ownership 并可打破 ownership cycle。这些资料不用于主张某一种 representation 普遍最优。  2 3

  67. AdaCore, SPARK User’s Guide 27.0w — Language Restrictions, Memory Ownership Policy, Pointer Support, Ownership, and Dynamic Memory Management, Applying SPARK in Practice。这些资料记录 SPARK 对 access value 的 ownership-based restriction、moving/borrowing/observing semantics,以及当前包含 cycle 或 sharing 的 pointer-based structure 通常位于支持的 ownership pattern 之外;指南还明确对比了支持的 linked list/tree 与不支持的 conventional doubly linked list/DAG。  2

  68. AdaCore, SPARK User’s Guide 27.0w — Formal Containers Library, Applying SPARK in Practice — Pointer-Based Data Structures。指南建议在实际可行时用 SPARK container abstraction 替代 pointer-intensive structure,提供 SPARK.Containers.Formal.Doubly_Linked_ListsSPARK.Containers.Formal.Unbounded_Doubly_Linked_Lists,区分不使用 dynamic allocation 的 bounded formal container 与使用 dynamic allocation 的 unbounded variant,并说明 GNATprove 可以针对 SPARK-visible contract 证明 client 的正确使用,但这并不因此证明 non-SPARK private implementation 满足 specification。这些边界把 explicit pointer-graph restriction 与 container-level availability 分开,也把 library implementation 保留为独立 trust/verification boundary。  2 3 4

  69. The Rust Programming Language, What Is Ownership?References and BorrowingValidating References with Lifetimes; The Rust Reference, Borrow operatorsPointer types — References。这些资料确认 move/copy 与 borrowing 行为、引用有效性规则、shared borrow 与 mutable borrow 的区别,以及生命周期标注表达关系而不是改变引用实际存活时间这一事实,同时也记录 lifetime inference/elision。本脚注只支持语言/编译器行为,不用于证明开发生产力效果。  2

  70. Shuofei Zhu et al., Learning and Programming Challenges of Rust: A Mixed-Methods Study, ICSE 2022; Will Crichton, Gavin Gray, and Shriram Krishnamurthi, A Grounded Conceptual Model for Ownership Types in Rust, OOPSLA 2023; Will Crichton and Shriram Krishnamurthi, Profiling Programming Language Learning, OOPSLA 2024; Rust Survey Team, 2024 State of Rust Survey Results。ICSE 研究把 100 个 Stack Overflow 问题的人工分析与 101 名 Rust programmer 的 survey 结合起来。OOPSLA 研究测量特定读者群体中的 ownership 理解与学习行为;2023 initial deployment 报告与 original version 相比 Ownership Inventory 平均高 9%(N = 342, d = 0.56),2024 研究分析 62,526 名读者和 1,140,202 条 quiz 回答,并报告 12 项干预后目标题目平均提高 20%。2024 State of Rust survey 有 7,310 份完整回答,约 92% 的受访者自我认定为 Rust 用户,约 31% 的非用户把 perceived difficulty 作为不使用 Rust 的主要原因,53% 的受访者把自己评价为能够 productive 地使用 Rust。这些都是 self-selected、面向 Rust 的 survey 结果,不是对组织层面生产力或一般开发者总体的直接估计。  2 3

  71. Rust Project, Rust Survey 2021 Results2025 State of Rust Survey ResultsLessons learned from the Rust Vision Doc processThe many journeys of learning Rust。2021 年工作场所采用数据——83% 认为采用过程 challenging、13% 报告 Rust 在采用期间让团队变慢、82% 表示 Rust 帮助团队实现目标——是受访者 self-report,而不是受控语言比较。2025 survey 收集了 7,156 份回答,并明确警告不要从约七千份回答以及更小的 optional-question 分母中过度外推;它把 slow compile time/storage usage 与 debugging 列为不可忽视的 productivity 问题。Vision Doc process 收集了 4,200 多份 survey 回答和 70 多次 interview,主要关注 individual developer experience 而非整个公司的测量,并记录了 selection bias,尤其是难以接触拒绝或停止使用 Rust 的人。其学习路径案例只能说明定性差异与可能的支持 pattern,不能说明出现频率、标准 ramp-up 期限或组织生产力的因果系数。  2

  72. Abraham Kaplan, The Conduct of Inquiry: Methodology for Behavioral Science, Chandler Publishing Company, 1964; Abraham H. Maslow, The Psychology of Science: A Reconnaissance, Harper & Row, 1966。Kaplan 的讨论与 Maslow 的 hammer 比喻支持把 familiarity 作为有关问题定义的方法论提醒。它们不是 software developer 的总体研究,也不是“学习 Rust 导致更广泛应用 Rust”的证据。 

  73. Len Bass, Paul Clements, and Rick Kazman, Software Architecture in Practice, 3rd Edition 与 publisher 的 sample chapter, “Choice of Technology,” p. 76。其 technology-choice 讨论明确包括可用技术与工具、组织内部 familiarity、外部 support、side effect,以及与既有 stack 的 compatibility;architecture framework 也把 quality attribute 与 constraint 作为设计输入。该来源支持多维选择标准,而不是 programming language 的排名。 

  74. Rust Survey Team, 2024 State of Rust Survey Results。survey 收到 7,310 份完整回答,约 92% 的受访者 self-identify 为 Rust 用户,Rust project 也说明该 survey 主要面向既有 Rust developer。在工作中使用 Rust 的受访者中,21% 表示因为已经熟悉 Rust,所以把它作为 default choice;报告还把 server backend、web/networking service 与 cloud technology 描述为 survey 中尤其常见的 technology domain。这些结果描述的是 Rust-oriented survey 样本;它们不能证明非理性的 tool bias、backend market share、比较生产力或普遍适用性。  2

  75. Rust Project, The Rust Reference — Functions: Async functionsstd::future::FutureAsynchronous Programming in Rust — Why Async?。这些来源确认 async call 会返回 future,Future::poll 是执行 interface,Rust 不提供 built-in async runtime,而且 Rust async 不强制要求 heap allocation 与 dynamic dispatch。它们并不证明 application 的总 runtime cost 为零。 

  76. Rust Project, Asynchronous Programming in Rust — Pinningstd::pin。文档解释了 compiler-generated future 的 address sensitivity、Pin contract,以及 pinning 暴露出来的 low-level case,并明确指出普通 async/await 用户往往不需要直接处理 pinning。 

  77. Rust Survey Team, 2024 State of Rust Survey Results; Rust Project, 2025 March Project Goals Update2026 Project Goals。survey 的 open answer 提到 async programming 与 debuggability 的困难,project-goal 记录中也包含持续改善 async ergonomics 与 Pin 的工作。这些资料说明它们是被认可的工作领域,但不是对发生率或比较 developer productivity 的 controlled estimate。 

  78. Rust Project, Asynchronous Programming in Rust — Why Async?; Tokio, tokio::runtimetokio::sync。这些来源展示了边界的两个方面:Rust 不提供 built-in runtime;Tokio 把 scheduler、I/O driver、timer service 组合提供,同时许多 Tokio synchronization primitive 是 runtime-agnostic 的,而部分依赖 timer 的 operation 则不是。因此不能从整个 ecosystem 推断 runtime coupling,而应逐 API 评估。 

  79. Rust Project, The Rust Reference — External blocks: FunctionsFunctions: Async functionsstd::future::Future。external block 中的 foreign declaration 不接受 async qualifier,而 Rust async function 生成的 future 的 poll interface 使用 Rust 特有的 PinContext。这些事实说明需要明确的 cross-language async protocol,但并不意味着只有 blocking 或 callback bridge 可行。 

  80. Rust Project, 2026 Project GoalsAsync Future Memory Optimisation。已接受的 2026 工作包括 async future memory 与 state-machine optimization。memory-optimization goal 记录了大型 nested-future layout,并报告与 stack overflow 以及 cloud、embedded、kernel 等 memory-constrained environment 相关的担忧。这些是关于仍在处理的 implementation limit 的 project problem statement 与 engineering evidence,不是覆盖所有 async Rust program 的 population-wide benchmark。 

  81. The Go Project, The Go Programming Language Specification — Go statements, Rust Project, The Rust Reference — Async functions。specification 确认了不同的执行 model:Go 的 go statement 启动 goroutine,而 Rust async function 返回一个在被 poll 时推进的 future。它们本身不能证明相对 latency、memory use、debugging difficulty 或 developer productivity。 

  82. Rust Project, core::result#[must_use] 与 rustc unused_must_use lintResultmust_use;忽略它默认产生 warning,可由 lint policy 提升为 error,但并非每个程序中固有的 hard error。 

  83. Rust Project, The Rust Reference — try propagation expressioncore::resultResult?Err 时提前返回,并用 From::from 转换 residual。  2

  84. Oracle, Java Language Specification, Java SE 26 — Chapter 11,尤其 §11.2。checked exception 必须 catch 或 declare;RuntimeExceptionError 系列是 unchecked。 

  85. Haskell 2010 Language Report、Microsoft F# — ResultsDiscriminated Unions。这些资料证明 Rust 之前已有类似 ADT 表达,但不证明对 Rust 的直接影响链。 

  86. Rust Project, Paniccatch_unwind 与 Cargo Profiles: panic。这些资料区分 unwind/abort、cleanup、恢复边界、target 限制与 profile policy。 

  87. Matthew Prince, “Cloudflare outage on November 18, 2025”, 2025-11-18。postmortem 记录 duplicated feature metadata、200-feature limit 与 Result::unwrap() 导致的 Rust panic,但不支持对 Rust production code 中 unwrap 使用作总体推断。 

  88. Rust Project, Cargo — Specifying DependenciesSemVer Compatibility。Cargo 以 left-most non-zero component 判断兼容;initial-development 规则是 convention 而非 hard guarantee。 

  89. Rust Project, Cargo — Publishing on crates.io。记录多个 owner 和 cargo yank;yank 不删除版本,也不破坏已有 lockfile。 

  90. Rust Secure Code Working Group, RustSec Advisory Database。advisory 与 cargo-audit 支持 vulnerability management,但不认证 crate 的总体质量。 

  91. Rust Survey Team, 2025 State of Rust Survey Results。7,156份回答、外推限制与 maintainer support 关注不能给出 registry-wide bus factor。 

  92. Rust Project Vision Doc group, “What we heard about Rust’s challenges”“Lessons learned from the Rust Vision Doc process”。后者记录了约4,200份 survey、70余次 interview、难以充分招募 Rust 怀疑者造成的 selection bias,以及资料不足以回答部分 domain 具体优先级问题的限制。前一篇文章的 original version 已被撤回;当前页面改为对团队从约70次 interview 中识别的 high-level challenge 加入 brief personal commentary,并明确警告这些 statements 比 Vision Doc 通常希望发布的内容更 biased。页面仍列出 crate discovery/trust 与部分 domain coverage 不成熟的问题;本书仅把它们作为 qualitative prompt,而不作为 registry-wide prevalence、平均质量或 ecosystem ranking 的证据。  2

  93. Rust Compiler Performance Working Group, “Rust compiler performance survey 2025 results”。3,700多份 self-selected 回答涵盖不同 build experience、平均6/10、selected-workload rebuild 与 IDE/CI;问题设计构成 inference boundary。  2 3

  94. Rust Compiler Development Guide, “Monomorphization”“Overview of the compiler”。concrete generic instance 可能增加 compile time/binary size,但只是 compiler pipeline 的一环。  2

  95. Rust Compiler Team, “Rust debugging survey 2026”。说明 tool/OS 质量差异与 visualizer、async、expression evaluation 等改进目标,不是比较生产力研究。 

  96. Rust Project, Cargo — Build Scripts。列出 C build、native library、generated module、platform configuration 与 change detection。 

  97. Rust Project, Cargo — FeaturesWorkspacesOptimizing Build Performance。说明 feature/resolver、workspace shared state 与 build trade-off。 

  98. Rust Compiler Performance Working Group, “Rust compiler performance survey 2025 results”; Rust Compiler Team, “Rust debugging survey 2026”。这些资料在各自 inference limit 内说明当前 build/editor observation 与 debugging goal,并不建立针对 Java/C# 或特定 IDE 的总体 maturity ranking。  2

  99. Rust Project, The Rust Programming Language — Performance in Loops vs. IteratorsThe Embedded Rust Book — Zero Cost Abstractions。前者以“不增加额外 runtime overhead”说明 iterator 的 zero-cost,并明确其 benchmark 边界;后者展示 zero-sized typestate 在 runtime 被消除的另一种 mechanism。两者都不证明整个 lifecycle 无成本。 

  100. Alpine Linux, Alpine 3.24.1 released, 2026-06-13, and the official v3.24 stable x86_64 package repositories. Measurement date: 2026-08-28. The measured APKs were busybox-1.37.0-r31.apk (SHA-256 0e626fa97cf937fda7bba4ed4dde8e2f2dbb5083ac34e02180cec0c4eba9351b), coreutils-9.11-r0.apk (18710a17a606d2454491d7e5b6114776c2ea861633234efdaee5b85fad5f2434), and uutils-0.9.0-r0.apk (4dfdc5be7b31965765b21573ea53fce49a0765db83b822ae8d6911ee9437e1b8). After extraction, file identified /bin/busybox, /bin/coreutils, and /bin/uutils as stripped dynamically linked x86-64 PIE executables; file sizes were measured directly from those ELF files. uutils-coreutils is a metapackage depending on uutils, so it was not used as the measured implementation. The snapshot does not normalize command coverage or shared-library dependency closure. 

  101. Rust Project, The rustc book — prefer-dynamicThe Rust Reference — Linkage。rustc 默认偏好 static dependency linkage,但在可用时也能优先 dynamic;Reference 定义 rlib、Rust dylib、system staticlibcdylib。 

  102. Rust Project, The Rust Reference — External blocks: ABIType layoutextern "Rust" 没有 stability guarantee,default Rust representation 的 layout guarantee 也有限;extern "C"repr(C) 提供显式 interoperability boundary。这不表示 dynamic Rust library 不受支持。  2 3 4

  103. Rust Project, The Cargo Book — Profiles。文档说明 s/z、debuginfo/strip、LTO、codegen-units、panic control 及 compile/link/runtime trade-off,并提醒 size-oriented optimization 不保证对所有 program 更小。 

  104. Rust Project, The Rust Reference — no_stdallocThe Embedded Rust Book — A no_std Rust Environmentno_std 使用 core;环境有 allocator 时,alloc 提供 VecBoxString 等 heap-backed type,而 startup、panic handling、allocator 与 platform integration 仍由 environment 负责。 

  105. Linux Kernel documentation, Rust Quick Start, documents CONFIG_RUST, the rust/ support code, samples/rust/, the complete LLVM setup as the best-supported build configuration, and GCC support for some configurations as very experimental. Direct inspection of the official Linux 7.2.1 stable source snapshot used for the cloc measurement also found Rust Binder under drivers/android/binder/ and Rust GPU drivers under drivers/gpu/drm/nova/ and drivers/gpu/drm/tyr/; the Nova and Tyr Kconfig help text marks them work in progress and potentially non-functional.  2

  106. Linux Kernel Archives, kernel.org, stable Linux 7.2.1, 2026-08-27. Measurement date: 2026-08-30. Artifact: linux-7.2.1.tar.xz, SHA-256 4158098c8a28ea8fbe068c855d3aa6341e03d06282add3cb9049f3a24e4557b3. Tool: Debian APT package cloc 2.04-1 (cloc v2.04). Procedure: extract the official tarball and run cloc . without additional options at the source root. The command reported 82,371 unique files, 30,518,591 total code lines, and 114,481 Rust code lines. This is a source-tree composition measurement, not a runtime-use, binary-size, defect-rate, or production-adoption metric.  2

  107. Linux kernel CVE record as reproduced by NVD, CVE-2025-68260, and the upstream fix 3e0ae02ba831da2b707905f4e602e43f8507b8cc. The record describes an unsafe removal from Rust Binder’s death_list, a concurrent list-access race and pointer corruption, and records Linux 6.18 as affected with 6.18.1 and 6.19-series fixes. It supports the specific unsafe-boundary failure analysis, not a defect-rate comparison between Rust and C kernel code.  2 3

  108. Ferrous Systems, Ferrocene Part 3: The Road to Rust in mission- and safety-critical, 2021;AdaCore, AdaCore and Ferrous Systems Joining Forces to Support Rust, 2022,以及 Announcements around Rust, 2023;Ferrous Systems, Officially Qualified - Ferrocene, 2023;Ferrocene, Qualification PlanSafety Manual - Qualification scope;Ferrous Systems, Ferrocene 26.02.0 now available!, 2026。Ferrous Systems 于2021年与其子公司 Critical Section GmbH 一同公开 Ferrocene,将其作为安全关键领域的 Rust 语言与编译器 qualification 项目。AdaCore 与 Ferrous Systems 于2022年宣布联合开发,并于2023年宣布结束这项联合开发合作。当前公开 qualification 资料记录了编译器在 ISO 26262 ASIL D/TCL 3、IEC 61508 class T3 与 IEC 62304 下的范围,以及 Safety Manual 的使用约束。2026年的 Ferrocene 资料把 TÜV SÜD qualification 表述为 ISO 26262 ASIL D、IEC 61508 SIL 3、IEC 62304 Class C;同时把 core 的已认证子集单独限定为 ISO 26262 ASIL B 与 IEC 61508 SIL 2,并把 DO-178C DAL C 描述为对客户认证活动的支持。这并不意味着使用 Ferrocene 构建的单个应用或系统会自动取得相应安全等级的认证。 Ferrous Systems, Ferrocene 26.05.0 now available!, 2026-07-28,说明最新 release 提供 TÜV SÜD-qualified compiler、ISO 26262 ASIL B / IEC 61508 SIL 2 的 certified core subset、面向 DO-178C DAL C 与 IEC 61508 SIL 4 的 customer certification support,并包含 upstream Rust 1.93.0 至 1.95.0 的变更。公开 mainEvaluation Plan - Qualification Scope 将 qualified tool 限定为 rustc,并把 companion development tool 区分为 unqualified,但页面自身警告它是可能 incomplete/inaccurate 的 development-branch preview。因此同一 main 的 Safety Manual/Core Certification 中的 rustc/core 1.99.0 只作为下一 rolling development snapshot 的 scope 信息,而不视为已发布 26.05.0 的 qualification version。  2 3

  109. Rust Survey Team, 2025 State of Rust Survey Results。调查收集 7,156 份回答,并报告计划继续招聘 Rust developer 的组织增加,同时提醒不要从其 Rust-oriented respondent population 与较小的 optional-question denominator 过度外推。它证明 Rust 相关 hiring activity,而不是语言间 labor-pool 或 wage ranking。 2025 survey 于2025-11-17至12-17进行;9,389人开始填写,7,156人完成(completion rate 76.2%)。报告明确警告不能从约7,000份回答中过度外推,而且 optional question 的 denominator 更小。因此 hiring graph 支持的是受调查的 Rust-oriented population 及其组织中的趋势,而不是 job posting census、劳动力市场总规模或跨语言 wage estimate。 

  110. CMU Software Engineering Institute, “The Growing Importance of Sustaining Software for the DoD: Part 1”。文章把 software sustainment 与物理磨损区分开,并说明 hardware/environment、requirement、defect、performance 的变化如何持续产生 maintenance 需求。  2

  111. Robert C. Seacord et al., CMU Software Engineering Institute, “Legacy System Modernization Strategies”, CMU/SEI-2001-TR-025。报告比较大型复杂 legacy system 的 modernization 方案,而不是把语言替换规定为 default。  2

  112. Google Android Security Team, “Rust in the Android platform”, “Eliminating Memory Safety Vulnerabilities at the Source”, and “Deploying Rust in Existing Firmware Codebases”。Google 记录了 new-code-first、interoperability 投资以及在既有低层 codebase 中 incremental/drop-in 使用 Rust,而不是要求整体重写成熟 C/C++ code。  2 3

  113. Google, “Rust in Android: move fast and fix things”, 2025, and Google Android Security Team, “Eliminating Memory Safety Vulnerabilities at the Source”, 2024。2025 Android report 在 Android 自身 development/security data 中比较 Rust 与 C/C++ 或 C++。这是针对该组织与 codebase 的强证据,但不是 randomized language experiment 或 industry-wide estimate。 

  114. Microsoft, “What’s new in Windows 11 Enterprise LTSC 2024”,记录 Windows 11 24H2 中 win32kbase_rs.sys 的 Rust GDI-region 实现。它证明 shipped Windows kernel use case,但不证明组织总体 language share 或 comparative defect rate。 

  115. Amazon Web Services, Open Source Security,说明 Firecracker 由 Rust 编写并支撑 AWS Lambda 等 serverless offering,EC2 team 对新的 AWS Nitro System component 使用 Rust。这是 production adoption case,不是 universal workload recommendation。 

  116. Emily M. Bender et al., On the Dangers of Stochastic Parrots: Can Language Models Be Too Big?, FAccT 2021; Youssef Mansour and Reinhard Heckel, Measuring Bias of Web-filtered Text Datasets and Bias Propagation Through Training, 2024/2025。上述资料讨论 Web 规模训练数据的组成、筛选与分布可能影响模型行为的一般风险和实验可能性。但它们都没有测量 Rust 与 Ada/SPARK 话语的分布,也没有测量特定模型中的 Rust 相关回答偏差,因此本书不会据此推断 Rust 特有的 LLM 放大效应。  2

  117. 本书的“银弹叙事(silver-bullet narrative)”是对 Frederick P. Brooks Jr. 在 No Silver Bullet — Essence and Accidents of Software Engineering, Computer 20(4), 1987, pp. 10-19 中“silver bullet”比喻的扩展,是本书采用的分析标签。Brooks 的论文并未研究 Rust 或某个技术共同体,该术语本身也不能证明任何 Rust 话语的频率或原因。本书仅用它识别把复杂问题中的条件性改进方案扩展为单一或普遍解决方案的论证。 

  118. Rust Project, Governance; Rust RFC Book, Project Goals 2025H1Project Goals 2026; Rust Project Goals, 2026 Overview。这些资料展示基于 RFC 的讨论、bottom-up 的 project-goal 提案与团队支持、资源与共识限制,以及 async ergonomics、low-level tooling 等被明确列出的改进工作。它们可以证明官方项目公开讨论未解决的问题与 trade-off,但不能代表所有非官方 Rust 话语的态度。  2 3 4 5

  119. Leon Festinger, A Theory of Cognitive Dissonance, Stanford University Press, 1957; Henri Tajfel and John C. Turner, An Integrative Theory of Intergroup Conflict, 原论文 1979 年,后续收录本 2000 年; Matteo Cinelli et al., The echo chamber effect on social media, PNAS 118(9), 2021。这些资料提供一般理论以及针对其他主题、平台的经验研究,并不是对 Rust 社区的研究。因此,本书不会仅凭这些资料判断 Rust 用户的内在动机或 Rust 空间是否存在回音室。  2 3

  120. Open Source Initiative, History of the Open Source Initiative; GNU Project, Free Software MovementWhat is Free Software?。OSI 记录说,1998 年创建 open-source 标签时,试图把协作开发的实用/business-case framing 与 free software 所关联的哲学、政治 framing 区分开来。GNU 资料则明确把 freedom 与 community 置于 free software 的核心价值。这里把这些一手资料用于说明,当时相关技术共同体并不能被还原成一个价值框架。 

  121. Eric S. Raymond, The Cathedral and the Bazaar,1997 年首次发表,后续修订。Raymond 用 bazaar 比喻包含不同 agenda 与 approach 的 Linux 开发世界。这是一位参与者具有影响力的同时代解释,不是代表 1990 年代全部 Linux 用户的概率样本。 

  122. The Jargon File, Version 4.2.2, 20 Aug 2000。这份历史 lexicon 把 hacker culture 描述为松散连接的多个 subculture,讨论 slang 表达共同经验以及 inclusion/exclusion 的作用,并记录 M$RTFM 的同时代用法。它证明 hacker slang 的存在,但不是测量全部 Linux 用户态度或这些表达频率的代表性样本。 

  123. ISRG Prossimo, A Safer High Performance AV1 Decoder, 2023; Stephen Crane and Khyber Sen, Porting C to Rust for a Fast and Safe AV1 Media DecoderOptimizing rav1d, an AV1 Decoder in Rust, 2024; memorysafety/rav1d。这些官方资料说明了 dav1d C code 的移植、native assembly 的复用、drop-in C API、upstream synchronization 目标,以及向 safe Rust 迁移过程中性能边界的处理方式。  2 3

  124. ISRG Prossimo, $20,000 rav1d AV1 Decoder Performance Bounty, 2025; rav1d v1.1.0 release, 2025。前者报告当时性能差距因 benchmark、input、platform 而异,约为 5%,并设置 bounty;后者记录了 backport dav1d 1.5.1 性能改进以实现同步。这些是特定时间点的性能与 maintenance 事实,不代表当前所有 platform 的性能差距。 

  125. Hacker News, Improving performance of original dav1d video decoder, 2025。讨论中提出了 assembly 复用的 safety scope、重复 backport 成本、codec expertise 与长期 support 可持续性等问题。本书仅把它作为证明公开批评存在及其论证结构的定性案例,不把参与者的数值主张或价值判断在未经独立验证的情况下当作事实。 

  126. Antony Flew, Thinking about Thinking: Or, Do I Sincerely Want to Be Right?, Fontana/Collins, 1975。Flew 所说的“No-true-Scotsman Move”,是指不接受一般化命题的反例,而是事后改变“真正”成员的定义,将反例排除在外。 

  127. Ronny Scherer、Fazilat Siddiq、Bárbara Sánchez Viveros, “The Cognitive Benefits of Learning Computer Programming: A Meta-Analysis of Transfer Effects”, Journal of Educational Psychology, 111(5), 2019, pp. 764–792, DOI: 10.1037/edu0000314。研究报告总体迁移效应为 g = 0.49、近迁移效应为 g = 0.75、远迁移效应为 g = 0.47。但它没有检验 Rust 特有效果或一般智力上升,还必须同时考虑研究设计和对照组类型造成的差异。 该 meta-analysis 综合了105项研究与539个 effect sizes。moderator analysis 显示,使用 untreated control 的研究得到的 transfer estimate 大于 treated/active control,published study 的 effect 也大于 gray literature;这些 design 与 publication 差异进一步限制 causal 或 population-wide interpretation。 

  128. Uniform Guidelines on Employee Selection Procedures, 29 C.F.R. Part 1607,尤其是 §1607.9 和 §1607.14。该指南仅适用于美国劳动法语境,但可作为一种方法论示例,说明选拔标准应与工作分析及经验效度相联系。 §1607.9 “No assumption of validity” 明确排除用 general reputation、label、promotional material、usage frequency、testimonial 和 anecdotal account 代替 validity evidence。§1607.14 要求 validity study 审查 job information,并通常采用适合 validation strategy 的 job analysis。这是美国劳动法 framework,不是普遍心理规律,也不是 Rust-specific 主张。 

  129. Rust Project, A note on the Trademark Policy Draft, 2023-04-12; Rust Foundation, Rust Trademark Policy Draft Revision – Next Steps, 2023-04-17; Rust Foundation, Trademark Policy: Review and Survey, 2022-08-10。这些资料记录了 2022 survey、2023-04-06 草案公开、十天 consultation、与 Project Directors、Trademark Working Group、法律顾问的协作、对 wider Project 纳入不足与 communication 问题的承认,以及草案没有立即实施而是进入 feedback review 与 revision 的边界。  2 3 4

  130. Rust Project Leadership Council, Next Steps on the Rust Trademark Policy, 2024-11-06; Rust Foundation, Rust Trademark Policy Updates, 2024-11-06。这些资料记录 revised 2024 draft、2023 feedback 中反复出现的 concern 类别、取消 package-name restriction 以及对 logo、merchandise、publication rules 的修改,并明确当时仍处于 final-feedback draft 阶段。它们说明提交意见中的趋势,并非所有 Rust 用户的意见分布。  2 3 4

  131. Rust Project, Governance 与 Rust Forge, Leadership Council — Relationship to the Rust Foundation; Rust Project Directors, January & February 2026 Project Director Update; Rust Foundation Board minutes, June 11, 2024。这些资料说明 Leadership Council、Project teams、Moderation team 的当前 Project 角色,Project Directors 在 Foundation Board 代表 Project 并负责 Foundation relationship 的结构,以及 trademark revision 作为单独 Foundation/Project interface 工作推进的边界。Rust Forge 也指出 Project Directors 的 Foundation-related purview 精确边界尚未完全规定,因此本书不比现有文档更精确地断言组织权力。  2

  132. Rust Foundation, Rust Language Trademark Policy Updates, Explained, 2025-01-23; Rust Foundation, Rust Language Trademark Policy, current page accessed 2026-08-30。前者记录包括 Project Directors 在内的 Foundation Board 最终批准及主要允许范围;当前 policy 区分 Leadership Council 的 Project governance 与 Foundation 的 trademark ownership/stewardship,并具体划分无需 approval 和需要 approval 的使用。  2

  133. National Security Agency, Software Memory Safety, originally November 2022, April 2023 Version 1.1。v1.1 建议在可行时从 C/C++、assembly 战略性转向 MSL,并把 Python、Java、C#、Go、Delphi/Object Pascal、Swift、Ruby、Rust、Ada 列为示例,同时说明不同 MSL 的保证范围不同,non-language hardening 仍然必要。该列表使用的是 “some examples”,并非某个 workload 的最终语言选择或排他性批准清单。  2

  134. National Security Agency and Cybersecurity and Infrastructure Security Agency, Memory Safe Languages: Reducing Vulnerabilities in Modern Software Development, June 2025, Ver. 1.0,以及 release notice。报告把 Ada、C#、Delphi/Object Pascal、Go、Java、Python、Ruby、Rust、Swift 作为示例,明确说明 MSL 不是 panacea,adoption 并非在所有 circumstance 中都现实;同时讨论用 interoperability 代替 complete rewrite 的集成方式,以及 MSL adoption 不现实情况下的 non-MSL hardening。  2 3 4 5

  135. Office of the National Cyber Director, Back to the Building Blocks: A Path Toward Secure and Measurable Software, February 2024。报告把 MSL 作为 strong security building block,同时讨论 existing codebase 的 hybrid migration、no-one-size-fits-all 边界,以及 hardware 与 formal methods 的补充作用。Space-system 部分把 Rust 作为满足无强制 GC 等条件的一个示例,同时明确仍需更多 fielded evidence、toolchain maturity 与 workforce development。  2

  136. Jeff Vander Stoep, Alex Rebert, “Eliminating Memory Safety Vulnerabilities at the Source”, Google Online Security Blog, September 25, 2024. 报告 Android 内存安全漏洞占比六年间从 76% 降至 24%,并说明优先安全编写新代码的策略。 

  137. Jeff Vander Stoep, “Rust in Android: move fast and fix things”, Google Online Security Blog, November 13, 2025. 提供 2025 年 Android 内存安全漏洞占比、约 500 万行 Rust 代码、基于一项发布前潜在漏洞的密度估计,以及代码审查和回滚资料。 

  138. Jesse Howarth, “Why Discord is switching from Go to Rust”, Discord Blog, February 4, 2020. 说明特定 Read States 服务的缓存与 GC 条件及重写结果,并明确不建议重写所有系统。 

  139. Yizhou Zhang, “How we built Pingora, the proxy that connects Cloudflare to the Internet”, Cloudflare Blog, September 19, 2022. 说明 CPU、内存下降的多重原因,包括连接复用、多线程结构和消除语言边界。 

  140. Arun Gupta, “Announcing the Firecracker Open Source Technology: Secure and Fast microVM for Serverless Computing”, AWS Open Source Blog, November 26, 2018. 给出 i3.metal、默认 microVM 大小与最小设备模型下低于 125 毫秒的启动时间。 

  141. Miguel Ojeda, “[PATCH] rust: conclude the Rust experiment”, Linux Kernel Mailing List, December 13, 2025. 说明实验结束与持续支持,并指出未完成组合和剩余工作。 

  142. Ilia Afanasiev, “Is Rust the Future of Programming?”, JetBrains Blog, May 13, 2025. 根据 2024 Developer Ecosystem 数据估计过去十二个月 Rust 用户 226.7 万、主语言用户 70.9 万。 JetBrains 的 Developer Ecosystem 2024 — MethodologyDeveloper Ecosystem Data Playground — Methodology 记录:2024年5–6月 survey 清理后包含171个国家和地区的23,262名 developer,并按 geography、employment status、language use 与 JetBrains-product use 加权,同时承认仍可能存在 response bias。population model 将 survey 中的 category share 与建模得到的各国 developer population 结合,并把所得 population figure 视为 estimate 而非 exact count。因此226.7万 / 70.9万是 population estimate,不是可识别 developer 的 census,也不是 Rust job opening 数量。 

  143. Rust Survey Team, “2025 State of Rust Survey Results”, Rust Blog, March 2, 2026. 报告 7,156 份回答并说明样本外推限制。 

  144. National Vulnerability Database, “CVE-2025-30388”. 记录 Windows Win32K-GRFX 堆缓冲区溢出和本地攻击向量,未归属 Rust 实现。 

  145. Ubuntu Security, “CVE-2025-68260”. 说明 Rust Binder unsafe 列表删除操作与并行访问如何造成数据竞争和指针损坏。 

  146. Rust Project Goals, “Just add async”, 2026. 说明同步与异步代码功能差距、同步析构限制及 2026—2027 年探索事项。 

  147. Defense Advanced Research Projects Agency, “TRACTOR: Translating All C to Rust”. 说明自动把遗留 C 翻译为 Rust 的研究计划目标和评价结构。 

  148. Rust Project Goals, 2026 GoalsC++/Rust Interop Problem Space Mapping。2026 goal list 将 C++/Rust interoperability 问题空间梳理作为继续进行的工作,详细资料明确承认大规模既有 C++ 资产以及渐进互操作的必要性。这并不是“全面重写永远不合理”的普遍命题,而是把互操作作为独立工程问题处理的官方依据。 

  149. Rust Project Goals, 2026 GoalsNormative Documentation for Sound unsafe Rust。官方 goal 包含 unsafe safety contract 的规范化文档、FLS、sanitizer、MC/DC coverage 等与高保证使用相关的工作。这些资料说明当前文档空白与计划,并不证明已经完成 certification,也不保证适用于所有 domain。 

  150. Rust Foundation, Rust Security Initiative; Rust Project Goals, Implement Verifiable Mirroring Prototype2026 contributor tasks。这些资料说明 ecosystem audit、threat modeling、cryptographically verified mirroring 以及 Cargo SBOM precursor 等当前工作。单个 goal 的存在并不能证明尚未部署功能的效果。