如何将C/C++项目重写为Rust?
摘要
本文讨论了将C/C++项目迁移到Rust的策略,强调增量迁移而非全面重写,并引用了Luca Palmieri和JetBrains的见解。
暂无内容
查看缓存全文
缓存时间: 2026/08/03 10:31
# 从 C++ 到 Rust 的迁移:Luca Palmieri(Mainmatter)访谈
来源:https://blog.jetbrains.com/rust/2026/07/27/cpp-to-rust-migration/
Rust 标志(https://blog.jetbrains.com/rust/)聚焦重要之事
## 如何将 C/C\+\+ 项目重写为 Rust?
*免责声明:本文借助 AI 生成,并由 JetBrains RustRover 团队审核。*
从 C 和 C\+\+ 迁移到 Rust 已经不再只是实验性的想法。如今,越来越多的团队开始将 Rust 视为一种实用方案,用以提升内存安全、降低长期维护成本,并现代化对性能要求严苛的系统。但一次成功的迁移,并不是因为 Rust 流行就把一切都重写。真正困难的问题更加实际:
***’‘为什么团队要考虑为现有的 C 或 C\+\+ 系统采用 Rust?这些系统中哪些部分应该迁移到 Rust?以及如何在不动摇现有成果的前提下完成迁移?’’*
c++ to rust migration这是我们近期直播中的主要话题之一,参与嘉宾包括**Mainmatter 的 Luca Palmieri**——*《100 Exercises To Learn Rust》(https://rust-exercises.com/100-exercises/)*以及即将出版的*《C to Rust Migration》(https://mainmatter.com/c-to-rust-migration-book/)*的作者——以及来自 JetBrains 的**Vitaly Bragilevsky**。Mainmatter 为在实际软件项目中采用 Rust 的团队提供支持,包括咨询、培训和迁移帮助。在直播中,Luca Palmieri 分享了这些实践经验所揭示的内容:哪些 C/C\+\+ 到 Rust 迁移项目能够成功,哪些通常会陷入困境,以及为什么增量迁移通常是更稳妥的路径。
完整直播视频可在此观看:
**Tldr:**对于许多生产系统而言,最稳妥的 C\+\+ 到 Rust 迁移策略并不是完全重写,而是增量迁移:从独立的模块开始,让 Rust 融入现有构建与发布流程,并随着信心的增长逐步扩展。
*相关资源:**Mainmatter 为计划或正在进行迁移项目的团队提供 Rust 咨询服务**(https://mainmatter.com/rust-consulting)*。*想深入了解迁移模式,可查阅**Mainmatter 的《C to Rust Migration》一书**(https://mainmatter.com/c-to-rust-migration-book/)*。*如果您的团队想先夯实 Rust 基础,**Luca Palmieri 的《100 Exercises To Learn Rust》**(https://academy.jetbrains.com/course/27805)*已作为 **JetBrains Academy(https://www.jetbrains.com/academy/)** 课程上线。*
## 为什么团队要从 C 和 C\+\+ 迁移到 Rust
几年前,建议从 C 或 C\+\+ 迁移到 Rust 可能感觉风险很大。没有人愿意做“矿井中的金丝雀”,尤其当项目承担重任、服务于生产流量或对业务至关重要时。如果团队要在迁移上投入多年的工程精力,他们需要确保不会在半路才发现障碍。
如今,这种犹豫已经减弱。像 Google 这样的公司不仅正在迁移到 Rust,他们还在发布数据,论证 Rust 的采用能够提升安全性(https://security.googleblog.com/2024/10/safer-with-google-advancing-memory.html),尤其是在减少内存安全漏洞和降低缺陷率方面,与其 C\+\+ 前身相比表现更优。除了降低风险之外,还有几个因素对今天的局面产生了影响:
- **专业知识正在扩散。**在一家公司学会了 Rust 的工程师会把这种知识带到下一个岗位,从而在整个行业产生乘数效应。
- **工具链已经成熟。**早期采用过程中令人痛苦的生态缺口大多已被填补。
- **招聘方面的顾虑正在消退。**当越来越多的开发者拥有 Rust 生产环境经验时,“我们找不到 Rust 开发者”的说法就失去了说服力。
- **AI 辅助降低了摩擦。**生成式 AI 工具有助于平缓学习曲线,让初始上手阶段不再那么令人生畏。
问题已经改变了。团队现在在问:他们的 C 或 C\+\+ 代码库是否存在一个看起来适合 Rust 解决的问题。想要更全面地了解这两种语言的对比,包括内存安全、性能和并发,请参阅我们的 Rust vs C\+\+ 比较(https://blog.jetbrains.com/rust/2025/12/16/rust-vs-cpp-comparison-for-2026/)。让我们来看看哪些项目应该迁移,以及如何迁移。
## 哪些项目应该迁移?
并非每个 C 或 C\+\+ 项目都能从 Rust 迁移中受益。对于业余项目,计算很简单:如果你想学习 Rust,或者觉得合适,就迁移。对于生产系统,迁移需要具备商业意义。最有力的候选对象通常是那些维护成本已经很高的代码库:
- **性能敏感型代码库**,为了榨取每一分效率,团队不得不采用难以推理的复杂模式。Rust 的安全保证不会牺牲性能,但确实能让这些复杂模式变得更易于管理。
- **并发或多线程系统**,借用检查器提供了在 C\+\+ 中难以复制的安全网。在 C\+\+ 中需要时刻警惕的数据竞争和内存安全问题,在 Rust 中会变成编译期错误。
- **安全关键型组件**,漏洞会带来高昂代价。如果你的代码是对攻击者有吸引力的目标,那么在生产环境之前防止内存安全问题的发生,具有明确的经济价值。
- **大规模部署**,即使很小的效率提升也能转化为可观的基础设施节约。如果迁移到 Rust 让你能在性能较弱的硬件上运行,这些节约会迅速累积。
共同的线索是可维护性。成功的迁移能够提升快速交付功能的能力,降低缺陷率,或者两者兼得。迁移成本必须通过减少返工、减少安全事件、提升开发者生产力或运营节约来获得合理性。
## C\+\+ 到 Rust 迁移:完全重写 vs\. 增量迁移
在完全重写和增量迁移之间做出选择,并非意识形态之争,而是取决于你的部署模式、代码库特征以及可用的测试基础设施。
完全重写听起来可能很有吸引力。你可以从零开始,按照自己希望的方式搭建代码库,按自己的喜好划分边界,把旧的决定抛在身后。但让我们看看,完全重写到底在什么情况下才合理?
### **何时对 C/C\+\+ 进行完全重写迁移到 Rust 是合理的**
- 代码库相对较小,范围可控
- 你有一套详尽的黑盒测试套件,能够在不假设内部结构的情况下验证行为
- API 表面定义良好且稳定
- 你掌控部署环境
以后端形式部署的服务是不错的候选对象。你可以将影子流量路由到新实现,将响应与旧系统进行比对,然后逐步转移负载。如果出了问题,你有多种手段可以拉闸:即时回滚、只路由极小比例的流量,或者将迁移限制在特定客户群体。
关键在于建立信心的机制。你需要能够证明新实现与旧实现行为一致的机制,包括用户可能不知不觉依赖的那些细微细节。
### 何时增量迁移更好
对许多团队而言,最稳妥的 C\+\+ 到 Rust 迁移路径是增量式的,尤其是对于大型、活跃或交付到客户手中的系统。你不是一次性替换整个代码库,而是迁移一块、发布一块、从中学习,然后继续。成功表现为稳步进展,理想情况下是不断加速的进展。某个版本可能包含 95% 的 C 或 C\+\+ 和 5% 的 Rust。之后的某个版本可能包含 90% 的 C 或 C\+\+ 和 10% 的 Rust。
随着时间推移,Rust 部分增长,旧代码收缩,团队持续关注重要的信号,如缺陷率、性能、用户反馈和开发速度。
这种方法的价值在于,每一块被迁移的部分都集成到了真实产品中。用户获得新代码。团队看到它表现更好还是更差。Bug 出现在正常的问题跟踪器中。迁移通过一个个版本不断积累信心。
理想情况下,Rust 代码越多,添加更多 Rust 就越容易。起步阶段是最困难的。一旦构建系统、测试设置、FFI 约定和发布流程就位,后续模块应该比第一个模块更容易。
当机构知识至关重要时,增量迁移也更有意义。如果逐块迁移,维护代码的开发者会在整个过程中持续参与。完全重写则存在知识丢失的风险:你最终可能得到结构更优的代码,但没有人记得某些决定当初为何做出。
## 从哪里开始:从叶子节点吃透模块图
一种实用的方法是查看模块图,找出孤立的模块。从叶子节点开始:那些没有依赖,或对系统其余部分只有少量依赖的模块。这通常是最容易的起点,因为第一批 Rust 代码不需要调用 C 或 C\+\+ 代码,只需要能够被现有 C 或 C\+\+ 代码库调用即可。
换句话说,Rust 模块暴露一个 extern API,但其内部仍然可以按正常 Rust 方式组织。这一点比看起来更重要。在编写有意义的 Rust 代码之前,你需要先解决集成问题:
- **Rust 如何融入现有构建系统?**
- **C、C\+\+ 和 Rust 代码如何链接在一起?**
- **内存清理器(memory sanitizers)是否仍能跨语言边界运行?**
- **在所有受支持的平台上是否都能正常工作?**
- **团队将如何测试和发布混合语言代码?**
从一个简单、低复杂度的模块开始,可以让你在攻克更困难的软件挑战之前,先解决这些问题。你希望交付一行几乎什么都不做、但能正确构建、正确链接并在所有 CI 流程中正常工作的 Rust 代码。
第一个模块完成后,你就解除了其他模块的依赖。接下来处理这些模块,逐步扩展你的 Rust 孤岛。最终,你会得到外围是 C、内部是 Rust 的结构,然后继续扩展,直到 C 消失。
缺点是你可能要在远离核心业务的模块上花费数月时间,这些模块可能多年无人触碰。这会让你感觉没有在增加业务价值。但你是在打下基础,让你能够重写那些复杂而重要的部分,而无需在底层管理 C 依赖。
## 另一种选择:垂直切片
相反的做法是让一个特定的用户流程或功能贯穿 Rust,切出一个垂直切片。这会让 Rust 代码立即处于关键路径上,从第一天起就展示业务价值。
挑战在于复杂性。你的 Rust 代码会不断调用 C,也不断被 C 调用。你会到处看到原始指针。这确实是 Rust,但感觉像 C 风格的 Rust。在很长一段时间内你不会获得安全收益,因为大部分动作发生在借用检查器能够验证的领域之外。
这种方法可能会让团队产生疑问:“这段 Rust 代码真的比它替换掉的 C\+\+ 更好吗?看起来和用起来都一样。”两种策略各有其价值。从叶子节点自下而上通常更干净,也允许更好的重构。垂直切片能更快展示业务价值,但需要更早面对更多复杂性。
## Rust FFI 是迁移中棘手的地方
增量迁移最困难的部分是跨越语言边界。在纯 Rust 内部,编译器会帮助强制所有权、借用和生命周期。你可以尝试一种设计,借用检查器会告诉你内存安全的故事是否成立。
一旦原始指针在 Rust 与 C 或 C\+\+ 之间穿越,这张安全网就会变弱。程序员必须手动跟踪各种假设:
- 这个指针还存活吗?
- 它是否有别名?
- 谁拥有这个值?
- 谁允许释放它?
在那一刻,你自己就成了借用检查器。这正是 Rust FFI 变得核心的原因。团队需要为所有权、分配和清理制定明确规则。
一个有用的原则是:谁分配内存,谁就该释放它。避免在 C 中分配而在 Rust 中释放,或者反过来,除非边界经过非常仔细的设计。在 C、C\+\+ 和 Rust 混合的代码库中,unsafe 代码是意料之中的。这并不意味着迁移是错误的。
它意味着 unsafe 代码需要被视为一个重要的设计面,而不是无人评审的胶水代码。大量迁移工作,是让 C 或 C\+\+ 中已经存在的行为,在 Rust 编译器眼中变得可见且正确。这可能感觉是艰苦的工作,但却是必不可少的。迁移到 Rust 的目的就是受益于静态分析,而代码必须以能让这些工具发挥作用的方式来组织。
## 在开始迁移之前要做什么
C\+\+ 到 Rust 的迁移不仅仅是一次重写。它是一个长期工程,会影响构建系统、发布流程、测试策略,以及之后维护代码的人。这就是为什么最稳妥的迁移往往是那些一步步建立信心的迁移。从小处着手,尽早解决集成问题,保持 Rust FFI 边界清晰可理解,并确保团队学到足够的 Rust 知识来接手新代码。
实际的要点很简单:C\+\+ 到 Rust 迁移,不是尽可能快地替换每一行代码,而是以降低风险、保留知识、让产品持续前进的方式,将系统中合适的部分迁移到 Rust。
#### 订阅 Rust Blog 更新
https://blog.jetbrains.com/rust/2026/07/27/cpp-to-rust-migration/#
## 探索更多
相似文章
从Go迁移到Rust
一份为Go开发者迁移到Rust编写的全面指南,专注于后端服务,对比正确性、运行时和人体工程学方面的权衡,并提供关于渐进式迁移的实用建议。
我们如何(及为何)将生产环境的C++前端基础设施重写为Rust
NearlyFreeSpeech.NET 将其生产环境的C++前端基础设施(nfsncore)重写为Rust,该系统负责所有传入请求的路由、缓存和访问控制。迁移的动机是Rust的安全性保证、性能、生态系统优势以及老化的C++代码库的局限性。
Cpp2Rust: 从C++到安全Rust的自动翻译
Cpp2Rust 是一个开源工具,利用 clang 的 AST 和一个运行时库,自动将 C++ 代码转换为安全的 Rust 代码,支持安全和 unsafe 两种输出模式,实现安全的内存安全转换。
从Rust到Ruby
开发人员描述使用LLM将一个15,000行的Rust Web应用转换为Ruby on Rails,发现Ruby版本明显更短,并评估了开发速度、安全性和可测试性方面的权衡。
Rust语言的性能
本次演讲分析了Rust相较于C++的性能优势与劣势,提供了基准测试和最佳实践。附有幻灯片和阅读材料。