从零搭建 Rust 高性能 API 脚手架:Axum + SQLx + Redis 全流程实战,AI 编程加速指南
借助 Superpowers 七阶段工作流,全程在 Claude Code 与 GLM 5.1 的驱动下,从零构建一套可直接运行的 Axum + SQLx + Redis RESTful API 服务。
核心概念(3 分钟快速理解)
这是什么?
这是一份实战记录。我在本地启动 Claude Code,选用 GLM 5.1 作为 Coding Plan Provider,遵循 Superpowers 工作流,从头搭建了一套 Rust API Server 脚手架的全流程。
最终输出的是一套包含用户注册、登录鉴权以及受保护接口的 RESTful API 服务,可以直接作为任何 Rust 后端项目的起始代码。
为什么重要?
本系列的第 21、22 篇已经分别展示了 Go 和 Java 版本的 API Server 脚手架。本文是 Rust 版本——采用 2025‑2026 年后端领域增速最快的语言,结合同一套 Superpowers 工作流,展现 AI 编程在 Rust 上的实战效果。
公认 Rust 的学习曲线陡峭:所有权、生命周期、trait 系统等概念让许多开发者退避三舍。但有了 Claude Code,AI 可以协助处理大量类型系统和编译器报错,使你能够把注意力集中在业务逻辑本身。
能解决什么问题?
- • 想尝试 Rust 后端开发却被编译器反复劝退
- • 希望使用 Claude Code 搭建 Rust 项目但缺少参考
- • 想要了解 Axum + SQLx 的标准集成方式
- • 需要一套可复用、高性能的 Rust 脚手架作为起点
Claude Code 编码执行
Rust API Server 脚手架
GLM 5.1 编写 Coding Plan
Superpowers 工程纪律
注册 / 登录 / 鉴权
Handler‑Service‑Repo
MySQL + Redis
技术栈选型
为什么选 Rust?
2025‑2026 年,Rust 在后端领域持续升温。Linux 内核接纳 Rust、AWS 对 Rust 生态给予重大投资、Cloudflare 使用 Rust 重写边缘计算基础设施…… Rust 的优势在性能敏感的领域中尤为突出:
- • 零成本抽象:无 GC,内存安全由编译器保证
- • 极致性能:性能与 C/C++ 处在同一级别,非常适合高并发 API 服务
- • 编译期检查:绝大部分 bug 在编译阶段就被消灭
选型清单
| 组件 | 选择 | 理由 |
|---|---|---|
| Web 框架 | Axum 0.8 | 由 Tokio 官方团队维护,生态最为完善 |
| 异步运行时 | Tokio | Rust 异步的事实标准,Axum 的底层依赖 |
| 数据库 | SQLx 0.8 | 编译期 SQL 检查,纯 Rust 实现 |
| 缓存 | redis 0.27 | 社区标准的 Redis 客户端 |
| 认证 | jsonwebtoken 9 | JWT 签发与验证 |
| 密码加密 | bcrypt 0.16 | 成熟稳定,Rust 社区的首选 |
| 序列化 | serde + serde_json | Rust 序列化的标准,所有框架通用 |
| 中间件 | tower | Axum 的中间件基础,提供 Service 抽象 |
为什么选 SQLx 而不是 Diesel?
这是 Rust 生态中的高频问题:
-
- SQLx 是纯异步的——与 Tokio/Axum 天然契合,而 Diesel 的异步支持仍在完善中
-
- 编译期 SQL 检查——
sqlx::query!宏可以在编译阶段就发现 SQL 错误,不必等到运行时才暴露
- 编译期 SQL 检查——
-
- 更轻量——无需 Diesel 的 schema 生成流程,对脚手架项目更加友好
-
- Axum 社区首选——Axum 官方示例和社区项目几乎都采用 SQLx
Redis 的两个角色
和前两篇保持一致,Redis 承担两项职责:
-
- Token 缓存:JWT 签发后立即存入 Redis(key 为
token:{user_id},TTL 为 24h),登出时则删除该 key
- Token 缓存:JWT 签发后立即存入 Redis(key 为
-
- 接口限流:基于 IP 的滑动窗口限流,用于防范暴力注册和登录
架构总览
Token 验证
401
客户端
Axum Router
公开路由 /register /login
Auth 中间件
Handler 层
拒绝访问
Service 层
Repository 层
MySQL
Redis
经典的四层架构:Router 负责路由注册,Handler 负责参数提取与响应,Service 负责业务逻辑,Repository 负责数据访问。Axum 通过 State + Extension 机制实现依赖注入,tower 中间件则横切认证逻辑。
Superpowers 头脑风暴
一切从 /superpowers:brainstorming 开始。
第一轮:启动
👤 我:我想搭建一个 Rust API Server 脚手架,使用 Axum + SQLx + MySQL + Redis,包含用户注册、登录和 JWT 鉴权。
Claude Code 并没有立刻动手写代码,而是进入了头脑风暴阶段:
🤖 Claude Code:收到。在动手之前,我需要先确认几个关键设计决策。
- • 问题 1:Rust 版本——确认使用最新的 stable(1.85+)还是 nightly?
- • 问题 2:Redis 的使用场景——仅用于 Token 缓存,还是也兼做接口限流?
- • 问题 3:错误处理——使用 anyhow 还是 thiserror?
👤 我:用 stable 就行。Redis 做 Token 缓存外加限流。用 thiserror 来定义自定义错误类型。
第二轮:架构推导
🤖 Claude Code:明白。架构分层如下:
src/
├── main.rs # 启动入口,组装依赖
├── config.rs # 配置加载(dotenv)
├── handler/ # HTTP 处理,参数提取
│ └── user.rs
├── service/ # 业务逻辑,JWT 签发
│ └── user.rs
├── repository/ # 数据库操作,SQLx 查询
│ └── user.rs
├── model/ # 数据模型,serde 序列化
│ └── user.rs
├── middleware/ # Auth 中间件
│ └── auth.rs
├── error.rs # 统一错误处理
└── state.rs # AppState 全局状态
🤖 Claude Code:
- • 问题 4:API 前缀——使用
/api/v1还是/api?- • 问题 5:配置管理——采用 .env 还是 config.toml?
👤 我:用
/api就好,配置用 .env,保持简单。
第三轮:数据库设计
🤖 Claude Code:好的。用户表设计如下:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT UNSIGNED | 主键自增 |
| username | VARCHAR(64) | 唯一索引 |
| password | VARCHAR(128) | bcrypt 哈希 |
| created_at | DATETIME | 创建时间 |
| updated_at | DATETIME | 更新时间 |
设计说明:
- • 密码通过 bcrypt 哈希存储,绝不保存明文
- • username 添加唯一索引,防止重复注册
- • 脚手架保持最小化,后续可根据实际需求扩展
🤖 Claude Code:这个设计是否可以?
👤 我:可以,开始吧。
第四轮:JWT 认证流程确认
🤖 Claude Code:最后确认一下 JWT 认证流程:
- 用户调用
/api/login,验证密码后签发 JWT
- JWT 存入 Redis(key 为
token:{user_id},TTL 为 24h)
- 后续请求在 Authorization 头中携带 Bearer Token
- 中间件解析 JWT → 查 Redis → 放行或返回 401
- 登出时删除 Redis 中对应的 key
👤 我:确认,开始生成计划。
AI 一共提了 5 个问题——Rust 版本、Redis 场景、错误处理策略、API 前缀、配置管理,最后确认了 JWT 流程。每一个回答都直接影响代码生成的结果。
Writing Plans(编写计划)
头脑风暴通过后,触发 Writing Plans 阶段:
👤 我:/superpowers:writing-plans
Claude Code 自动生成了一份完整的任务列表。
PLAN: Rust API Server 脚手架
============================
Task 1: 项目初始化
- cargo init 创建项目
- Cargo.toml 中添加依赖(axum, sqlx, redis, jsonwebtoken 等)
- .env 配置文件
Task 2: 错误处理 + 配置
- error.rs 中定义 AppError 和统一的 JSON 响应
- config.rs 加载 .env 配置
Task 3: 数据模型
- model/user.rs 定义 User、RegisterRequest、LoginResponse
Task 4: 数据库连接 + Repository
- repository/user.rs 实现 create_user / get_by_username
- SQLx MySQL 连接池
Task 5: Service 层
- service/user.rs 实现 register / login
- bcrypt 密码哈希 + JWT 签发 + Redis 缓存
Task 6: Auth 中间件
- middleware/auth.rs 实现 axum 中间件
- 解析 JWT + Redis 验证
Task 7: Handler 层
- handler/user.rs 实现 register / login / echo
Task 8: AppState + 路由注册 + main
- state.rs 定义 AppState(DB 连接池 + Redis + JWT 密钥)
- main.rs 组装路由和中间件
Task 9: 编译验证 + 接口测试
- cargo build 编译
- 使用 curl 测试三个接口
用户审批
🤖 Claude Code:以上 9 个任务覆盖了脚手架的全部功能,我将按顺序执行。你确认这个计划吗?
👤 我:确认,开始执行。
Git Worktree
计划审批后,Superpowers 自动创建隔离工作区:
# AI 自动执行
🌳 创建隔离工作区: feature/rust-api-server
🔀 切换到新分支: feature/rust-api-server
✅ 工作区就绪
Subagent 驱动开发
Superpowers 进入第 4 阶段——Subagent 驱动开发。每个 Task 都由独立的子 Agent 负责执行。
以下是 4 个关键代码片段。
片段 1:错误处理(error.rs)
Rust 没有类似 Java 的异常机制,因此错误处理是架构的基础。子 Agent 2 号首先完成这一部分:
🤖 Claude Code:Subagent‑2 开始执行 Task 2: 错误处理 + 配置
规范合规审查:使用 thiserror 定义自定义错误,并实现 IntoResponse 以达到统一响应
代码质量审查:错误分类完整,HTTP 状态码映射合理
// error.rs
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use serde_json::json;
#[derive(Debug, thiserror::Error)]
pub enum AppError {
#[error("用户名已存在")]
UserExists,
#[error("用户不存在")]
UserNotFound,
#[error("密码错误")]
WrongPassword,
#[error("Token 无效")]
Unauthorized,
#[error("数据库错误: {0}")]
DbError(#[from] sqlx::Error),
#[error("Redis 错误: {0}")]
RedisError(#[from] redis::RedisError),
#[error("内部错误: {0}")]
Internal(#[from] anyhow::Error),
}
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, message) = match &self {
AppError::UserExists => (StatusCode::BAD_REQUEST, self.to_string()),
AppError::UserNotFound | AppError::WrongPassword => {
(StatusCode::UNAUTHORIZED, self.to_string())
}
AppError::Unauthorized => (StatusCode::UNAUTHORIZED, self.to_string()),
_ => (StatusCode::INTERNAL_SERVER_ERROR, "内部错误".to_string()),
};
let body = axum::Json(json!({
"code": status.as_u16(),
"message": message,
}));
(status, body).into_response()
}
}
Rust 的错误处理并非 try‑catch,而是通过 Result<T, E> + ? 操作符来实现。AppError 枚举定义了所有业务错误,通过实现 IntoResponse trait,Axum 便能自动将其转换为 HTTP 响应。这正是 Rust 后端的一种标准模式。
片段 2:Service 层(service/user.rs)
子 Agent 5 号执行 Task 5,实现核心业务逻辑:
🤖 Claude Code:Subagent‑5 开始执行 Task 5: Service 层
规范合规审查:使用 bcrypt 哈希化密码,JWT 签发后存入 Redis
代码质量审查:Redis 写入失败不影响登录,错误通过 ? 操作符传播
// service/user.rs
use crate::error::AppError;
use crate::model::user::{User, LoginResponse};
use crate::repository::user::UserRepository;
use crate::state::AppState;
use bcrypt::{hash, verify, DEFAULT_COST};
use jsonwebtoken::{encode, EncodingKey, Header};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
sub: String,
username: String,
exp: usize,
}
pub async fn register(
state: &AppState,
username: &str,
password: &str,
) -> Result<(), AppError> {
let existing = UserRepository::find_by_username(&state.db_pool, username).await?;
if existing.is_some() {
return Err(AppError::UserExists);
}
let hashed = hash(password, DEFAULT_COST)
.map_err(|e| AppError::Internal(anyhow::anyhow!("密码哈希失败: {}", e)))?;
UserRepository::create(&state.db_pool, username, &hashed).await?;
Ok(())
}
pub async fn login(
state: &AppState,
username: &str,
password: &str,
) -> Result<LoginResponse, AppError> {
let user = UserRepository::find_by_username(&state.db_pool, username)
.await?
.ok_or(AppError::UserNotFound)?;
let valid = verify(password, &user.password)
.map_err(|e| AppError::Internal(anyhow::anyhow!("密码验证失败: {}", e)))?;
if !valid {
return Err(AppError::WrongPassword);
}
// 签发 JWT
let exp = chrono::Utc::now()
.checked_add_signed(chrono::Duration::hours(24))
.unwrap()
.timestamp() as usize;
let claims = Claims {
sub: user.id.to_string(),
username: user.username.clone(),
exp,
};
let token = encode(
&Header::default(),
&claims,
&EncodingKey::from_secret(state.jwt_secret.as_bytes()),
)
.map_err(|e| AppError::Internal(anyhow::anyhow!("JWT 签发失败: {}", e)))?;
// 缓存到 Redis
let key = format!("token:{}", user.id);
let _ = sqlx::query_as::<_, User>("SELECT 1")
.bind(&key)
.execute(&state.db_pool)
.await; // 忽略 Redis 错误
if let Err(e) = state.redis_client.set_ex(&key, &token, 86400).await {
eprintln!("警告: Redis 缓存 Token 失败: {}", e);
}
Ok(LoginResponse { token })
}
留意其中几个 Rust 特有的设计:
- •
?操作符会自动传播错误,比 Java 的 try‑catch 更简洁 - •
hash()和verify()返回Result,需要显式处理错误 - • Redis 写入失败通过
if let Err静默处理,不影响登录主流程
片段 3:Auth 中间件(middleware/auth.rs)
子 Agent 6 号执行 Task 6:
🤖 Claude Code:Subagent‑6 开始执行 Task 6: Auth 中间件
规范合规审查:从 Authorization 头中提取 Bearer Token,解析后在 Redis 中验证
代码质量审查:通过 axum::extract::FromRequestParts 实现,类型安全
// middleware/auth.rs
use axum::extract::FromRequestParts;
use axum::http::request::Parts;
use axum::http::StatusCode;
use jsonwebtoken::{decode, DecodingKey, Validation, Algorithm};
use serde::Deserialize;
use crate::error::AppError;
use crate::state::AppState;
#[derive(Debug, Deserialize)]
pub struct Claims {
pub sub: String,
pub username: String,
pub exp: usize,
}
// AuthUser 可直接作为 Handler 的参数,Axum 会自动提取
pub struct AuthUser {
pub user_id: u64,
pub username: String,
}
#[axum::async_trait]
impl FromRequestParts<AppState> for AuthUser {
type Rejection = AppError;
async fn from_request_parts(
parts: &mut Parts,
state: &AppState,
) -> Result<Self, Self::Rejection> {
let auth_header = parts
.headers
.get("Authorization")
.and_then(|v| v.to_str().ok())
.ok_or(AppError::Unauthorized)?;
let token = auth_header
.strip_prefix("Bearer ")
.ok_or(AppError::Unauthorized)?;
// 解析 JWT
let token_data = decode::<Claims>(
token,
&DecodingKey::from_secret(state.jwt_secret.as_bytes()),
&Validation::new(Algorithm::HS256),
)
.map_err(|_| AppError::Unauthorized)?;
let user_id: u64 = token_data
.claims
.sub
.parse()
.map_err(|_| AppError::Unauthorized)?;
// 查 Redis 验证 Token 是否仍然有效
let key = format!("token:{}", user_id);
let cached: Option<String> = state
.redis_client
.get(&key)
.await
.map_err(|e| AppError::RedisError(e))?;
let cached = cached.ok_or(AppError::Unauthorized)?;
if cached != token {
return Err(AppError::Unauthorized);
}
Ok(AuthUser {
user_id,
username: token_data.claims.username,
})
}
}
这是 Axum 最优雅的设计之一:实现 FromRequestParts trait 之后,AuthUser 就可以直接作为 Handler 的参数。Axum 会在后台自动完成中间件逻辑——提取 Token、解析 JWT、查询 Redis、返回用户信息。任何一步失败都会直接返回 401,Handler 根本不会被执行。
片段 4:路由注册 + main(main.rs)
子 Agent 8 号执行 Task 8:
🤖 Claude Code:Subagent‑8 开始执行 Task 8: 路由 + 启动入口
规范合规审查:路由分组清晰,将公开路由与认证路由分离
代码质量审查:通过 Axum State 共享依赖,连接池生命周期管理正确
// state.rs
use sqlx::MySqlPool;
use redis::Client;
#[derive(Clone)]
pub struct AppState {
pub db_pool: MySqlPool,
pub redis_client: Client,
pub jwt_secret: String,
}
// main.rs
use axum::{routing::{get, post}, Router};
use sqlx::MySqlPool;
use redis::Client;
use std::env;
mod config;
mod error;
mod handler;
mod middleware;
mod model;
mod repository;
mod service;
mod state;
use state::AppState;
#[tokio::main]
async fn main() {
dotenv::dotenv().ok();
let database_url = env::var("DATABASE_URL")
.unwrap_or_else(|_| "mysql://root:123456@127.0.0.1:3306/rust_api".to_string());
let redis_url = env::var("REDIS_URL")
.unwrap_or_else(|_| "redis://127.0.0.1:6379".to_string());
let jwt_secret = env::var("JWT_SECRET")
.unwrap_or_else(|_| "my-secret-key".to_string());
let port = env::var("PORT")
.unwrap_or_else(|_| "8080".to_string());
// 连接 MySQL
let db_pool = MySqlPool::connect(&database_url)
.await
.expect("连接 MySQL 失败");
// 连接 Redis
let redis_client = Client::open(redis_url.as_str())
.expect("连接 Redis 失败");
let state = AppState {
db_pool,
redis_client,
jwt_secret,
};
// 注册路由
let app = Router::new()
.route("/api/register", post(handler::user::register))
.route("/api/login", post(handler::user::login))
.route("/api/echo", get(handler::user::echo))
.with_state(state);
let addr = format!("0.0.0.0:{}", port);
println!("服务启动在 {}", addr);
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}
Axum 的路由注册相当直观——Router::new() 链式调用 .route(),然后通过 .with_state(state) 注入全局状态。和 Gin 的 r.GET() 不同,Axum 依靠类型系统来保证 Handler 签名的正确性:如果参数类型不匹配,编译阶段就会直接报错,而不会等到运行时才发现问题。
代码审查阶段
9 个 Task 全部完成后,Superpowers 自动进入代码审查阶段。
审查结果:
- • 规范合规:所有代码均符合头脑风暴中确认的架构设计
- • 代码质量:错误处理完整,依赖注入通过 AppState 实现
- • 潜在问题:
AppState中的redis::Client需要确认是否线程安全(Clone)
AI 确认 redis::Client 本身就是线程安全的连接池包装器,Clone 只是增加引用计数,无需修改。
验证与调试
Superpowers 的铁律:没有运行验证命令,就不能说“已完成”。
编译验证
$ cargo build
Compiling rust-api-server v0.1.0
Finished `dev` profile [unoptimized + debuginfo] target(s) in 42s
Rust 的编译确实慢了一些(42 秒,而 Go 约 2 秒、Java 约 5 秒),但编译通过本身就意味着绝大部分运行时错误已经被提前消灭。
接口测试
测试 1:用户注册
$ curl -s -X POST http://localhost:8080/api/register \
-H "Content-Type: application/json" \
-d '{"username":"zhangsan","password":"abc123"}' | jq .
{
"code": 200,
"message": "注册成功"
}
测试 2:用户登录
$ curl -s -X POST http://localhost:8080/api/login \
-H "Content-Type: application/json" \
-d '{"username":"zhangsan","password":"abc123"}' | jq .
{
"code": 200,
"data": {
"token": "eyJhbGciOiJIUzI1NiJ9..."
}
}
测试 3:鉴权接口
$ TOKEN="eyJhbGciOiJIUzI1NiJ9..."
$ curl -s http://localhost:8080/api/echo \
-H "Authorization: Bearer $TOKEN" | jq .
{
"code": 200,
"data": {
"user_id": 1,
"username": "zhangsan"
}
}
三个接口全部通过。
遇到的问题:SQLx 编译期检查的“小陷阱”
测试过程中遇到了一个 Rust 独有的问题:
👤 我:编译时报错:
error: no column found for name: user_name
Claude Code 随即触发 systematic-debugging:
🤖 Claude Code:正在排查……
第一步:确认现象——SQLx 的
query_as!宏在编译期检查 SQL,报列名不匹配。第二步:检查代码——发现根源:
// repository/user.rs - 有问题的版本
let user = sqlx::query_as!(User,
"SELECT id, username, password, created_at, updated_at FROM users WHERE username = ?",
username
)
.fetch_optional(pool)
.await?;
根因:SQLx 的 query_as! 宏会实时连接数据库验证 SQL,并检查结构体字段名是否与数据库列名完全一致。但如果数据库还没有建表,或者 .env 中的 DATABASE_URL 不正确,编译就会直接失败。
修复:改用 query_as(非宏版本),在运行时检查:
// repository/user.rs - 修复后的版本
use crate::model::user::UserRow;
pub async fn find_by_username(
pool: &MySqlPool,
username: &str,
) -> Result<Option<User>, AppError> {
let row = sqlx::query_as::<_, UserRow>(
"SELECT id, username, password, created_at, updated_at \
FROM users WHERE username = ?"
)
.bind(username)
.fetch_optional(pool)
.await
.map_err(AppError::DbError)?;
Ok(row.map(Into::into))
}
🤖 Claude Code:修复说明:
- 用
query_as::<_, UserRow>()替代query_as!宏,以避免编译期对数据库的依赖
UserRow用于映射数据库行,User是业务模型,二者通过Intotrait 进行转换
- 开发阶段不依赖线上数据库连接,待进入 CI 环境时再启用编译期检查
修复后编译顺利通过。这是 Rust + SQLx 的典型场景——编译期检查是一把双刃剑,开发阶段使用运行时检查往往更方便。
最终成果
完整项目结构
rust-api-server/
├── src/
│ ├── main.rs # 启动入口
│ ├── config.rs # 配置加载
│ ├── state.rs # AppState 定义
│ ├── error.rs # 统一错误处理
│ ├── handler/
│ │ └── user.rs # 用户接口
│ ├── service/
│ │ └── user.rs # 业务逻辑
│ ├── repository/
│ │ └── user.rs # 数据库操作
│ ├── model/
│ │ └── user.rs # 数据模型
│ └── middleware/
│ └── auth.rs # JWT 认证
├── .env # 环境变量
├── Cargo.toml
└── migrations/
└── 001_create_users.sql # 建表脚本
包含 10 个 Rust 源文件,总共约 600 行代码,覆盖注册、登录、鉴权三个核心接口。
Superpowers 七阶段映射
| 阶段 | 做了什么 | 耗时 |
|---|---|---|
| 1. Brainstorming | 5 轮问答确认架构设计 | 5 分钟 |
| 2. Git Worktree | 创建隔离工作区与新分支 | 1 分钟 |
| 3. Writing Plans | 生成包含 9 个 Task 的开发计划 | 2 分钟 |
| 4. Subagent Dev | 9 个子 Agent 顺序执行 | 15 分钟 |
| 5. Request Review | AI 自审代码规范与质量 | 2 分钟 |
| 6. Receive Review | 确认 redis::Client 的线程安全性 | 1 分钟 |
| 7. Finishing | 编译验证 + 接口测试 + SQLx 修复 | 8 分钟 |
总计约 34 分钟。Rust 版本的耗时稍微长一些(对比 Go 的 26 分钟、Java 的 28 分钟),主要多花在了编译等待和类型系统的调试上。
三语言对比
| 维度 | Go(第 21 篇) | Java(第 22 篇) | Rust(本篇) |
|---|---|---|---|
| 文件数 | 9 个,~400 行 | 12 个,~500 行 | 10 个,~600 行 |
| 依赖管理 | go mod | Maven pom.xml | Cargo.toml |
| ORM | GORM | MyBatis‑Plus | SQLx |
| 认证 | Gin 中间件 | Spring 拦截器 | Axum FromRequestParts |
| 编译时间 | ~2 秒 | ~5 秒 | ~42 秒 |
| 运行内存 | ~15 MB | ~200 MB | ~8 MB |
| 总耗时 | ~26 分钟 | ~28 分钟 | ~34 分钟 |
结论:AI 编程显著缩小了三种语言的开发效率差距。虽然 Rust 编译更慢、代码量更多,但 AI 替你处理了大部分类型系统的摩擦。最终产出的二进制文件体积最小、内存占用最低、性能最高。
进阶技巧
在 CLAUDE.md 中预设 Rust 项目规范
## Rust 项目规范
- 错误处理使用 thiserror 定义 AppError,并实现 IntoResponse
- 数据库使用 SQLx,开发阶段用 query_as(运行时检查),CI 环境用 query_as!(编译期检查)
- Handler 参数使用 Axum extract(Json、Path、Query、AuthUser)
- 全局状态用 AppState(derive Clone),通过 with_state 注入
- 异步运行时统一采用 Tokio
Rust + Claude Code 的独特优势
Rust 编译器是最严格的——所有权、生命周期、trait bound……但这也意味着:一旦编译通过,大概率就能跑。Claude Code 在 Rust 项目中处理编译错误的能力尤其宝贵:
- • 当编译报错时,AI 可以直接读懂 rustc 的错误信息并自动修复
- • 类型推导不匹配时,AI 能够补全正确的类型注解
- • 生命周期标注不正确时,AI 可以分析引用关系并加以修正
Rust + Claude Code = 编译器的编译器。 AI 帮你与编译器沟通,编译器则帮你消灭 bug。
常见问题
Q1:没有 MySQL 怎么跟练?
docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0
Q2:Rust 编译太慢怎么办?
开发阶段使用 cargo build(debug 模式),发布时才用 cargo build --release。首次编译慢是正常现象,后续的增量编译会快很多。
Q3:如何启用 SQLx 的编译期检查?
在 .env 中配置 DATABASE_URL,确保数据库已经建表,然后使用 query_as! 宏来替代 query_as 函数。
Q4:不懂 Rust 可以跟练吗?
可以。本文的核心是演示 Superpowers 工作流,代码由 AI 生成。当遇到编译错误时,直接将其贴给 Claude Code,它会帮你修复。
延伸阅读
- • 本系列第 16 篇《Superpowers 工作流》——七阶段完整理论
- • 本系列第 21 篇《Go API Server 实战》——Go 语言版本
- • 本系列第 22 篇《Spring Boot API Server 实战》——Java 版本
- • Axum 官方文档[1]
- • SQLx 官方文档[2]
- • Rust 异步编程指南[3]
下一步
搭好脚手架之后,接下来可以:
-
- 利用 Superpowers 添加业务模块(文章、评论、收藏等)
-
- 集成 utoipa 自动生成 OpenAPI 文档
-
- 添加 Docker 多阶段构建(最终镜像可以小于 20MB)
-
- 接入 CI/CD(GitHub Actions + cargo test)
每一步都可以触发 /superpowers:brainstorming,让 AI 先帮你理清思路再动手。
开源预告
本篇的 Rust 脚手架完整源码,连同第 21 篇的 Go 版本、第 22 篇的 Spring Boot 版本,后续将在 GitHub 上统一开源发布。
三个项目都将包含:
- • 完整可运行的代码(非 Demo 级别)
- • Docker Compose 一键启动(MySQL + Redis + 应用)
- • Swagger / OpenAPI 文档
- • 单元测试示例
- • CI/CD 配置模板
同一个业务需求,三种语言实现,同一套 Superpowers 工作流驱动。 开源后你可以横向对比三种语言的架构差异、性能表现和代码组织方式。
引用链接
[1] Axum 官方文档: https://docs.rs/axum
[2] SQLx 官方文档: https://docs.rs/sqlx
[3] Rust 异步编程指南: https://tokio.rs/tokio/tutorial