Rust 编码风格¶
此文件扩展 common/coding-style.md,并添加 Rust 特定内容。
格式化¶
- 强制使用 rustfmt — 提交前务必运行
cargo fmt - 使用 clippy 进行 lint —
cargo clippy -- -D warnings(将警告视为错误) - 4 空格缩进(rustfmt 默认)
- 最大行宽:100 字符(rustfmt 默认)
不可变性¶
Rust 中的变量默认是不可变的 — 请利用这一点:
- 默认使用
let。仅在需要可变性时使用let mut - 优先返回新值,而不是就地修改
- 如果不确定函数是否需要分配,请使用
Cow<'_, T>
use std::borrow::Cow;
// 良い例 — デフォルトで不変、新しい値を返す
fn normalize(input: &str) -> Cow<'_, str> {
if input.contains(' ') {
Cow::Owned(input.replace(' ', "_"))
} else {
Cow::Borrowed(input)
}
}
// 悪い例 — 不要なミューテーション
fn normalize_bad(input: &mut String) {
*input = input.replace(' ', "_");
}
命名¶
遵循标准 Rust 约定:
- 函数、方法、变量、模块、crate 使用 snake_case
- 类型、trait、枚举、类型参数使用 PascalCase(UpperCamelCase)
- 常量和静态变量使用 SCREAMING_SNAKE_CASE
- 生命周期:短小写('a、'de)— 复杂情况下使用描述性名称('input)
所有权与借用¶
- 默认使用借用(
&T)。仅在需要存储或消费时获取所有权 - 不要在不理解根本原因的情况下,仅为满足借用检查器而克隆
- 函数参数中,优先接受
&str而不是String,&[T]而不是Vec<T> - 对于需要拥有
String的构造函数,使用impl Into<String>
// 良い例 — 所有権が不要な場合は借用する
fn word_count(text: &str) -> usize {
text.split_whitespace().count()
}
// 良い例 — Into を使用してコンストラクタで所有権を取得する
fn new(name: impl Into<String>) -> Self {
Self { name: name.into() }
}
// 悪い例 — &str で十分なのに String を取得する
fn word_count_bad(text: String) -> usize {
text.split_whitespace().count()
}
错误处理¶
- 使用
Result<T, E>和?进行传播 — 生产代码中不要使用unwrap() - 库:使用
thiserror定义类型化错误 - 应用程序:使用
anyhow处理灵活错误上下文 - 使用
.with_context(|| format!("failed to ..."))?添加上下文 - 仅在测试和真正不可达的状态中使用
unwrap()/expect()
// 良い例 — thiserror によるライブラリエラー
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
#[error("failed to read config: {0}")]
Io(#[from] std::io::Error),
#[error("invalid config format: {0}")]
Parse(String),
}
// 良い例 — anyhow によるアプリケーションエラー
use anyhow::Context;
fn load_config(path: &str) -> anyhow::Result<Config> {
let content = std::fs::read_to_string(path)
.with_context(|| format!("failed to read {path}"))?;
toml::from_str(&content)
.with_context(|| format!("failed to parse {path}"))
}
优先使用迭代器而非循环¶
转换优先使用迭代器链。复杂控制流使用循环:
// 良い例 — 宣言的で合成可能
let active_emails: Vec<&str> = users.iter()
.filter(|u| u.is_active)
.map(|u| u.email.as_str())
.collect();
// 良い例 — 早期リターンを伴う複雑なロジックにはループ
for user in &users {
if let Some(verified) = verify_email(&user.email)? {
send_welcome(&verified)?;
}
}
模块结构¶
按领域而不是按类型组织:
src/
├── main.rs
├── lib.rs
├── auth/ # ドメインモジュール
│ ├── mod.rs
│ ├── token.rs
│ └── middleware.rs
├── orders/ # ドメインモジュール
│ ├── mod.rs
│ ├── model.rs
│ └── service.rs
└── db/ # インフラストラクチャ
├── mod.rs
└── pool.rs
可见性¶
- 默认是私有的。内部共享使用
pub(crate) - 仅对 crate 公共 API 的一部分使用
pub - 从
lib.rs重新导出公共 API
参考¶
有关全面的 Rust 惯用法和模式,请参见技能:rust-patterns。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 ev/ECC