该技能针对 Rust 代码的编写、审查、重构、调试与讲解,内容提炼自五个来源:Google Rust Style Guide、官方 Rust API Guidelines、Effective Rust(David Drysdale)、Rust Design Patterns(rust-unofficial)和 Microsoft 的 Pragmatic Rust Guidelines。当这些来源互相冲突时,技能会说明应遵循哪一条以及原因。
编码心态:写“Rust 形状”的代码,不要把 C++、Java、C# 或 Python 的构造直接照搬过来。用 Result 表达错误,用所有权和 Drop 表达资源,用 trait 和 enum 表达多态,用 Option 表达可空性;通过 Deref 模拟“基类”、Manager/Factory 类型、throw_if_null 辅助函数等做法都是坏味道。让非法状态无法表示:把不变量推进类型(用 enum 代替 bool 标志和“若 Y 则必须为 X”的注释,用 newtype 表示单位和 ID,用可失败构造器一次性完成校验)。应用代码不同于库代码:库代码要严格遵循 API 设计规则,应用代码应偏向简单直接,使用具体类型、anyhow 风格错误、Vec 返回值,不做投机性泛化。让工具承担机械工作:rustfmt 负责格式,clippy 负责习惯检查,编译器负责内存安全,把注意力留给设计。
提交前的检查:运行 cargo fmt、cargo clippy --all-targets --all-features -- -D warnings、cargo test,以及库项目运行 cargo doc --no-deps,并修复其报告的全部问题。修复 lint 而不是静默它;确实需要抑制时用 #[expect(clippy::name, reason = "...")] 限定到最窄范围,#[allow] 只用于生成代码或宏输出。不要在源码中写 #![deny(warnings)],应在 CI 中把警告视为错误。lint 在 Cargo.toml 的 [lints.rust]、[lints.clippy] 或 [workspace.lints] 中集中配置。
所有权与借用:优先唯一所有权,仅在共享所有权是设计的一部分时用 Rc/Arc,仅在需要内部可变性时用 RefCell/Mutex。不要为了安抚借用检查器而 clone;可先尝试延长临时值、拆分长表达式、用 std::mem::take/replace 或 Option::take 移出字段、拆分大结构体、有意识地 clone 小型不可变数据,把索引或 Rc<RefCell<_>> 加 Weak 回指作为最后手段。参数接受最通用的借用类型(&str 而非 &String,&[T] 而非 &Vec<T>,&T 而非 &Box<T>,Option<&T> 而非 &Option<T>);只在需要所有权时按值取 T;结构体字段优先持有所有数据;设置完成后用 let data = data; 冻结可变性;公共签名中不要出现 Rc、Arc、Box、RefCell。
类型与 API 设计:命名方面,类型、trait、变体用 UpperCamelCase(缩写视为一个词,如 Uuid、HttpClient),函数与方法用 snake_case,常量用 SCREAMING_SNAKE_CASE,类型参数与生命周期用短名;getter 不加 get_ 前缀,转换前缀 as_ / to_ / into_ 表示代价与所有权;避免 Service、Manager、Factory、Helper、Util 等含糊后缀。用 newtype 表达语义区分,公共签名中不用 bool 参数,用 Option 表达缺失,用 data-carrying enum 代替“字段 X 仅在 Y 时有效”。积极派生标准 trait(Debug、Clone、Copy、PartialEq/Eq、PartialOrd/Ord、Hash、Default),实现 Display、From/TryFrom、FromStr、FromIterator/Extend、IntoIterator;Deref 只用于智能指针和容器。提供 new() 并与 Default 保持一致;超过两个可选参数或构造过程需要校验时改用 builder(build() 返回 Result 并完成全部校验)。默认私有,逐步放宽可见性;跨 crate 的公共 enum 与公共字段结构体加 #[non_exhaustive];不需要下游实现的 trait 予以封存(sealed);每个公共项只在唯一路径暴露;serde 实现放在名为 serde 的 feature 之后。trait 只用于泛型编程或扩展 trait,优先具体类型,其次泛型,再次 dyn Trait;trait 必需方法保持最少并给默认实现;有明确接收者的函数写成方法;闭包使用最通用的 Fn* 约束;宏只在函数、泛型、trait 无法胜任时使用。重构他人代码时修复请求涉及的所有坏味道,保持公共行为不变,保留并标注看不懂的怪癖;模块无测试时先用测试固定当前行为。
错误与 panic:缺失是常态时用 Option,调用方需要知道原因时用 Result,代码内部 bug 或不变量被违反时用 panic!/assert!/expect("原因")。panic 不是异常,不能用于报告错误输入,不能依赖 catch_unwind 做控制流,库中不能捕获 panic 后继续。每个有意 panic 都要带相关信息;优先 expect("原因") 而非 unwrap();用模式匹配代替先检查再 unwrap;锁中毒视为致命(.lock().expect("lock poisoned"))。库的公共错误类型要实现 std::error::Error、满足 Send + Sync + 'static、为包装原因实现 source(),不得使用 ()、String 或 Box<dyn Error>;Display 消息小写、简洁、无尾随标点。资料在“实现 From<Upstream> 以便 ? 转换”处中断,后续内容暂未提供。