使用 Claude Code 和 Codex 编写 Rust
I’m happy to translate the article for you, but I’ll need the full text of the post (the content you’d like translated). Please paste the article’s body here, and I’ll provide a Simplified‑Chinese version while keeping the source line, formatting, code blocks, URLs, and technical terms unchanged.
Source:
为什么 Rust 让 AI 辅助开发感觉像实时代码审查
有一段时间,我一直在尝试 AI 编码工具,当你把 Rust 与 Claude Code 或 OpenAI 的 Codex 这类代理结合使用时,会出现一些令人着迷的现象。与使用 Python 或 JavaScript 的体验根本不同——这归结为一个简单的事实:Rust 的编译器充当了每一次 AI 编辑的自动专家审查员。
- 如果能编译,它可能就能工作——这不仅是 Rust 的座右铭;它正成为可靠 AI 辅助开发的基石。
- 当你让 Claude Code 或 Codex 在 Python 代码库上“大显身手”时,你本质上是相信 AI 能自行正确完成任务。确实,你可能有 linter 和类型提示(如果你足够幸运),但没有严格的强制执行:AI 可以生成看起来合理、通过快速审查的代码,却在生产环境中因某个没人想到的边缘案例而崩溃。
而在 Rust 中,编译器会在任何代码运行之前捕获这些问题。
| 问题类型 | Rust 的处理方式 |
|---|---|
| 内存安全事故 | 编译期捕获 |
| 数据竞争 | 编译期捕获 |
| 生命周期问题 | 编译期捕获 |
这形成了一个异常紧密的反馈回路,AI 编码工具能够实时学习。
Rust 对 AI 编码有什么特别之处?
编译器不仅仅说“错误”,然后让你去猜。它会准确指出出了什么问题、问题出在哪里,甚至常常给出修复建议——这对 Codex 或 Claude Code 之类的 AI 工具来说是绝对的金矿。
示例 1 – 从拥有的 String 返回引用
fn get_first_word(s: String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
编译器输出
error[E0106]: missing lifetime specifier
--> src/main.rs:1:36
|
1 | fn get_first_word(s: String) -> &str {
| - ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value,
but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
1 | fn get_first_word(s: String) -> &'static str {
| ~~~~~~~~
编译器实际上在向 AI 解释所有权模型:“嘿,你正尝试返回一个引用,但你所引用的东西在函数结束时会被丢弃——这行不通。”
- 结构化、确定性的反馈——错误码
E0106、精确位置、清晰解释,甚至还有建议的修复。 - 真正的修复当然是把函数签名改为借用而不是获取所有权。
示例 2 – 并发错误
use std::thread;
fn main() {
let data = vec![1, 2, 3];
let handle = thread::spawn(|| {
println!("{:?}", data);
});
handle.join().unwrap();
}
编译器输出
error[E0373]: closure may outlive the current function, but it borrows `data`
--> src/main.rs:6:32
|
6 | let handle = thread::spawn(|| {
| ^^ may outlive borrowed value `data`
7 | println!("{:?}", data);
| ---- `data` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src/main.rs:6:18
|
6 | let handle = thread::spawn(|| {
| ^^^^^^^^^^^^^
help: to force the closure to take ownership of `data`, use the `move` keyword
|
6 | let handle = thread::spawn(move || {
| ++++
编译器直接告诉 AI:“在这里加 move。” Claude Code 或 Codex 能解析这条信息,应用修复,然后继续——无需猜测、无需抱有侥幸心理,也不会出现导致生产系统崩溃的运行时数据竞争。
与 Python / JavaScript 的区别
当 AI 在这些语言中生成有缺陷的并发代码时,你可能直到在特定负载条件下触发竞争条件才会发现问题。而在 Rust 中,错误永远不会通过编译器。
“Rust 对于 Claude Code 在更大任务上进行无人监督的工作非常出色。强大的类型系统与严格的安全检查相结合,像一位专业的代码审查员,自动拒绝错误的编辑并防止 bug 的产生。”
— Julian Schrittwieser,Anthropic
这与我们在 Sayna 的经验相吻合,我们在 Rust 中构建了整个语音处理基础设施。当 Claude Code(或任何 AI 工具)进行更改时,编译器会立即告知出错的原因。无需等待运行时错误,也不需要调试会话来弄清音频流为何随机崩溃——错误信息清晰且可操作。
典型工作流程
# AI generates code
cargo check
# Compiler output:
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
--> src/main.rs:4:5
|
3 | let r1 = &x;
| -- immutable borrow occurs here
4 | let r2 = &mut x;
| ^^^^^^ mutable borrow occurs here
5 | println!("{}, {}", r1, r2);
| -- immutable borrow later used here
- AI 看到此错误,理解借用冲突后,重新组织代码。
- AI 进行修改 并再次运行
cargo check。
cargo check
# No errors – we’re good
这里的关键在于 每一个错误都有唯一的错误码(本例中为 E0502)。运行 rustc --explain E0502 会得到包含示例的完整解释。AI 工具可以利用这些信息,不仅了解 出了什么问题,还可以明白 为什么 Rust 的所有权模型会阻止这种模式,因为编译器在代码生成过程中本质上在“教”AI。
结论
当编译器提供 结构化、确定性的反馈,且 AI 能够解析并据此行动时,错误容忍度会变得极低。将其与那些缺乏强大编译时保证的语言进行比较,Rust 在 AI 辅助开发中的优势显而易见。
当 C++ 编译器在模板出错时
error: no matching function for call to 'std::vector>::push_back(int)'
vector v; v.push_back(42);
^
当然,它会告诉你类型不匹配,BUT 想象一下,如果这个错误埋在 500 行的模板回溯中,而你必须找一个 AI 来准确解析它。
Rust 的错误信息被设计成人类可读,这恰好使它们对 AI 来说非常友好:每个错误都包含精确的源代码位置(行号和列号)、违规规则的解释、(在可能的情况下)修复建议,以及指向详细文档的链接。
当 Claude Code 或 Codex 运行 cargo check 时,它会收到一个 structured error,可以直接对其进行处理。反馈循环以秒计,而不是调试会话。
为什么 CLAUDE.md 文件有帮助
在 Sayna,让我们的开发工作流显著提升的一个因素是投入了一个正确的 CLAUDE.md 文件——这是一份放在仓库中的指南文档,为 AI 编码工具提供关于项目结构、约定和最佳实践的上下文。
对于 Rust 项目,特别需要包含的内容:
- Cargo 工作区结构 – 你的 crate 如何组织。
- 错误处理模式 – 你使用
anyhow、thiserror还是自定义错误类型? - 异步运行时 – 使用的是 Tokio、async‑std 还是其他?
- 测试约定 – 集成测试位置、mock 模式。
- 内存管理指南 – 何时使用
Arc、Rc或普通引用。
Rust 严格的编译器加上文档完善的项目指南,能够为 AI 工具营造一个高度可信的环境;它们了解规则,而编译器会强制执行这些规则。
Sayna 的真实案例
在 Sayna——处理 WebSocket、音频处理管道、实时 STT/TTS 提供者抽象——我们使用 Rust 来完成所有繁重的工作。这正是需要内存安全和并发保证的系统类型。
当 Claude Code 重构我们的 WebSocket 消息处理器时,它不会意外地“吃掉”它们;当它修改我们的音频缓冲区管理时,也不会产生使用后释放(use‑after‑free)错误,因为该语言根本不允许这种情况。
pub async fn process_audio_chunk(&self, chunk: Bytes) -> Result {
let processor = self.processor.lock().await;
processor.feed(chunk)?;
while let Some(result) = processor.next_result().await {
self.tx.send(result).await?;
}
Ok(())
}
AI 工具可能需要多次迭代才能正确处理借用和生命周期,但每一次迭代都由具体的编译器错误指引:没有猜测,没有抱有侥幸的期待。
Rust 为 OpenAI 的 Codex CLI 提供动力
OpenAI 最近将他们的 Codex CLI 完全重写为 Rust。这样做不仅仅是为了性能——虽然这确实是一个因素——他们明确指出 Rust 能在编译时消除整类 bug。如果 OpenAI 在自己的 AI 编码基础设施上押注 Rust,这就说明了它的发展方向。
安全影响极大:Codex 现在在使用 Rust 安全保证结合操作系统隔离(Linux 上的 Landlock,macOS 上的 Sandbox‑exec)的沙盒环境中运行。当 AI 生成的代码在你的机器上执行时,拥有编译时的安全保证是不可或缺的。
使用 AI 来驯服生命周期
我不会假装 Rust 很容易学习,因为所有权模型需要时间去内化,而生命周期在你刚入门时可能会让人沮丧——AI 编码工具实际上在处理 Rust 的锋利边缘方面相当出色。
我最喜欢的技巧是让 Claude Code “修复生命周期”,让它找出 &、ref、as_ref() 和显式生命周期标注的组合,使我的代码能够编译,而我则专注于实际的逻辑和架构。
// Before: Claude, fix this
fn process(&self, data: Vec) -> &str {
&data[0] // Won’t compile – returning reference to local data
}
// After: Claude’s solution
fn process(&self, data: &[String]) -> &str {
&data[0] // Works – borrowing from input parameter
}
这实际上是一种比单独苦苦挣扎于编译器错误更好的学习 Rust 的方式:你会看到模式,理解为什么某些做法有效,并且当你提问时,AI 会解释它的推理过程。
Rust + AI 开发建议
- 投入到你的
CLAUDE.md– 记录你的模式、约定和架构决策。AI 会遵循它们。 - 积极使用
cargo clippy– 启用所有 lint。反馈越多,AI 输出越好。 - 使用严格检查的 CI – 确保在每次更改时运行
cargo test、cargo clippy和cargo fmt;AI 工具可以在你查看之前验证它们的工作。 - 从明确的任务开始 – 当边界清晰时,Rust 的类型系统发挥光彩:先定义你的 trait 和类型,然后让 AI 实现逻辑。
- 验证但仍要信任 – 编译器能捕获很多问题,但并非全部:逻辑错误仍可能漏掉,因此代码审查仍然必不可少。
AI 辅助系统编程的未来
我们正处于一个有趣的拐点:Rust 在系统编程领域快速增长,AI 编码工具也开始在生产工作中发挥作用。这两者的结合产生的效果远超各自的简单相加。
在 Sayna,我们的语音处理基础设施负责实时音频流、多个供应商的集成以及复杂的状态管理——全部使用 Rust 构建,并得到了大量 AI 的辅助。这意味着我们可以更快推进项目,而不必时刻担心内存错误或竞争条件。
如果你曾尝试过 Rust,却觉得学习曲线陡峭,不妨再次尝试,配合 Claude Code 或 Codex 作为你的结对编程伙伴。当有 AI 能够帮助你处理所有权和借用模式时,你可以更专注于构建实际功能,体验会大不相同。
The tools are finally catching up to the promise of the language.