静态形式系统的边界:从 Rust 到软件工程的资源语义

2026年07月13日

Rust 是一门在特定历史背景下诞生的语言。Mozilla 希望寻找一种能够兼顾底层性能与内存安全的系统语言,以减少 C/C++ 长期存在的内存错误。Rust 围绕所有权、借用检查和生命周期建立了一套高度一致的静态形式系统,在它所针对的问题范围内取得了重要成功。这种成功并不仅属于 Rust,也代表了近年来软件工程不断强化编译期约束、追求静态正确性的整体趋势。

然而,静态形式系统终究存在边界。这个边界并非来自类型系统设计得还不够复杂,而是来自软件本身所面对的问题域。软件不是封闭的数学对象,而是持续与现实世界发生交互的动态系统。程序真正创造价值,并不是因为它通过了类型检查,而是因为它不断地产生效应:写入数据库、发送网络请求、驱动硬件、协调分布式节点、响应用户行为。真正需要面对的对象,不是静态程序,而是不断变化的历史状态。

因此,编译器能够验证的是程序在当前约束下是否满足某些形式性质,却无法验证这些程序在不断演化的问题域中是否仍然符合业务目标。一个 `Result<T, E>` 可以保证错误被显式处理,却无法判断错误处理策略是否符合业务要求;一个生命周期能够证明引用不会悬垂,却无法判断对象是否应该继续存在。软件的正确性始终包含两个层面:形式正确性与语义正确性。前者属于编译器,后者属于开发者以及业务世界。

这一点在裸内存管理上体现得尤为明显。长期以来,人们不断寻找统一、安全、自动化的内存管理方案,从垃圾回收、引用计数,到 RAII、Region、Ownership,各种语言不断提出新的抽象。然而,这些方案始终没有形成真正意义上的统一答案,并不是因为算法还不够先进,而是因为裸内存管理本身并不是一个单纯的内存问题,而是资源生命周期的语义问题。

事实上,内存只是众多资源中的一种。文件描述符、网络连接、GPU 缓冲区、DMA 缓冲区、数据库事务、锁、共享内存,都具有类似的生命周期:创建、共享、转移、释放。语言能够表达对象生命周期,却无法预先定义资源在业务中的语义生命周期。对象何时析构可以由语言决定,而资源何时真正完成使命,则取决于业务本身。HTTP 长连接什么时候关闭、数据库事务什么时候提交、缓存什么时候失效、订单什么时候真正结束,这些都不是类型系统能够推导出来的问题,而是业务语义本身。

因此,当一个系统真正需要直接管理裸内存时,内存管理往往已经成为业务逻辑的一部分,而不是独立于业务之外的技术细节。开发者真正管理的并不是一块内存,而是资源在整个业务流程中的生命周期。任何语言都只能预设某一种生命周期模型,并在这一模型内尽可能提高安全性和自动化程度;但业务世界本身不断变化,没有任何一种预设语义能够覆盖所有场景。因此,资源管理不存在放之四海而皆准的统一方案,这并不是语言设计的失败,而是开放问题域的客观特征。

这也说明,所有权系统并不是资源管理的最终答案,而是众多资源语义中的一种表达方式。当业务语义能够自然映射到唯一所有者、有限借用和静态生命周期时,Rust 的抽象能够显著降低错误发生的概率;而当系统需要表达复杂图结构、跨语言接口、自引用对象或历史状态时,开发者仍然需要重新回到业务语义本身进行设计。此时,语言提供的是工具,而不是最终判断。

类似的边界同样存在于所有形式化方法之中。数学并不直接研究现实世界的绝对真理,而是在既定公理体系下研究必然成立的关系。现代数学越来越强调的是“在当前假设下可以推出什么”,而不是“世界本身究竟是什么”。软件工程亦是如此。编译器能够证明的是程序满足当前约束,而不是未来所有约束。当需求发生变化、业务规则不断演化时,新的约束需要重新建立,新的程序需要重新生成。软件工程最大的困难,并不是一次性证明程序正确,而是在变化中持续保持系统正确。

因此,与其说软件开发是在寻找一个永远正确的程序,不如说是在不断调整约束,使程序持续适应不断变化的问题域。真正的软件生命周期并不是“程序—结束”,而是“约束—程序—状态—效应—历史—反馈—新的约束”的持续循环。程序只是这一循环中的一个阶段,而不是终点。

飞控系统恰好提供了一个值得借鉴的例子。对于毫秒级的空中碰撞检测,人类反应速度远远不足,因此必须依赖自动化系统完成快速而确定的响应;而面对传感器异常、环境突变、任务目标变化等复杂情形,人类又能够综合经验、上下文与价值判断作出新的决策。这里并不存在“相信机器”还是“相信人”的简单对立,而是不同时间尺度采用不同控制方式。机器负责快速、局部、确定性的控制,人负责慢速、整体、适应性的判断,两者共同构成系统的完整能力。

软件系统同样具有类似的分层。静态类型系统、形式验证和自动分析适合承担那些能够明确形式化、需要快速验证的工作;而业务建模、需求演化、异常处理以及资源生命周期设计,则需要开发者不断根据现实世界调整自己的理解。任何试图依赖单一形式系统覆盖“快速确定性响应”与“慢速适应性判断”两个时域的努力,都不可避免地会在一个方向约束过强,而在另一个方向能力不足。

因此,静态形式系统真正的价值,并不是替代人的判断,而是将那些能够稳定形式化的问题尽可能交给机器完成,从而让开发者能够把更多精力投入到真正属于人的工作——理解业务、设计资源语义、应对变化、持续演化系统。

从这个意义上说,软件工程并不存在一种能够彻底解决正确性的终极语言,也不存在一种能够覆盖所有资源生命周期的统一模型。形式系统能够降低局部复杂度,却不能消除开放世界的不确定性;类型能够约束对象,却不能定义业务;编译器能够证明程序满足当前约束,却不能替代开发者理解不断变化的问题域。资源协调本质上属于运行中的系统组织问题,而不是静态程序表示问题。

真正成熟的软件工程,并不是追求一个永远不会出错的系统,而是建立一个能够在变化中持续修正、持续适应、持续演化的系统。工具负责处理能够形式化的问题,人负责理解无法形式化的世界。两者并不是彼此替代,而是共同构成现代软件工程不可或缺的两个方面。
 

Logo

开放原子旋武开源社区(简称“旋武社区”)是由开放原子开源基金会孵化及运营的技术社区,致力于在中国推广和发展Rust编程语言生态,推动Rust在操作系统、终端设备、安全技术、基础软件等关键领域的产业落地,构建安全、可靠、高效的软件基础设施。

更多推荐