使用 Claude Code 和 Codex 编写 Rust

发布: (2025年12月29日 GMT+8 12:04)
15 min read
原文: Dev.to

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 编码工具,当你把 RustClaude CodeOpenAI 的 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
  1. AI 看到此错误,理解借用冲突后,重新组织代码。
  2. 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 如何组织。
  • 错误处理模式 – 你使用 anyhowthiserror 还是自定义错误类型?
  • 异步运行时 – 使用的是 Tokio、async‑std 还是其他?
  • 测试约定 – 集成测试位置、mock 模式。
  • 内存管理指南 – 何时使用 ArcRc 或普通引用。

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 “修复生命周期”,让它找出 &refas_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 开发建议

  1. 投入到你的 CLAUDE.md – 记录你的模式、约定和架构决策。AI 会遵循它们。
  2. 积极使用 cargo clippy – 启用所有 lint。反馈越多,AI 输出越好。
  3. 使用严格检查的 CI – 确保在每次更改时运行 cargo testcargo clippycargo fmt;AI 工具可以在你查看之前验证它们的工作。
  4. 从明确的任务开始 – 当边界清晰时,Rust 的类型系统发挥光彩:先定义你的 trait 和类型,然后让 AI 实现逻辑。
  5. 验证但仍要信任 – 编译器能捕获很多问题,并非全部:逻辑错误仍可能漏掉,因此代码审查仍然必不可少。

AI 辅助系统编程的未来

我们正处于一个有趣的拐点:Rust 在系统编程领域快速增长,AI 编码工具也开始在生产工作中发挥作用。这两者的结合产生的效果远超各自的简单相加。

在 Sayna,我们的语音处理基础设施负责实时音频流、多个供应商的集成以及复杂的状态管理——全部使用 Rust 构建,并得到了大量 AI 的辅助。这意味着我们可以更快推进项目,而不必时刻担心内存错误或竞争条件。

如果你曾尝试过 Rust,却觉得学习曲线陡峭,不妨再次尝试,配合 Claude Code 或 Codex 作为你的结对编程伙伴。当有 AI 能够帮助你处理所有权和借用模式时,你可以更专注于构建实际功能,体验会大不相同。

The tools are finally catching up to the promise of the language.

Back to Blog

相关文章

阅读更多 »

Tesla现在比以往更智能

构建与集成 Grok 与 Tesla Maps:智能导航未来的瞥见 将 Grok 这样的 AI 系统与 Tesla Maps 集成不会…