帮助开发者掌握地道 Rust 模式、所有权、并发与错误处理实践
复制安装指令,让 AI 自动完成配置 · 推荐新手
请帮我安装 askskill 上的 "rust-patterns" 技能: 1. 下载 https://raw.githubusercontent.com/affaan-m/ECC/main/skills/rust-patterns/SKILL.md 2. 保存为 ~/.claude/skills/rust-patterns/SKILL.md 3. 装好后重载技能,告诉我可以用了
请检查这段 Rust 代码的错误处理方式,指出不符合惯用法的地方,并用 Result、thiserror 或 anyhow 给出更清晰安全的重构建议,解释每处修改原因。
返回一份带说明的重构建议,涵盖错误类型设计、传播方式与可维护性改进。
我正在编写一个 Rust 并发模块,请根据需求推荐合适的并发模式,比较 Arc、Mutex、RwLock、mpsc 和 tokio 任务的适用场景,并给出示例结构。
输出并发设计建议、模式选型理由,以及线程安全的示例代码框架。
请分析这段 Rust API 设计中的 trait、生命周期和所有权用法,指出哪些地方可以更符合惯用 Rust 风格,并给出提升性能与可读性的修改建议。
得到一份 API 设计审查结果,包含 trait 抽象、借用策略与性能优化建议。
Idiomatic Rust patterns and best practices for building safe, performant, and maintainable applications.
This skill enforces idiomatic Rust conventions across six key areas: ownership and borrowing to prevent data races at compile time, Result/? error propagation with thiserror for libraries and anyhow for applications, enums and exhaustive pattern matching to make illegal states unrepresentable, traits and generics for zero-cost abstraction, safe concurrency via Arc<Mutex<T>>, channels, and async/await, and minimal pub surfaces organized by domain.
Rust's ownership system prevents data races and memory bugs at compile time.
// Good: Pass references when you don't need ownership
fn process(data: &[u8]) -> usize {
data.len()
}
// Good: Take ownership only when you need to store or consume
fn store(data: Vec<u8>) -> Record {
Record { payload: data }
}
// Bad: Cloning unnecessarily to avoid borrow checker
fn process_bad(data: &Vec<u8>) -> usize {
let cloned = data.clone(); // Wasteful — just borrow
cloned.len()
}
Cow for Flexible Ownershipuse std::borrow::Cow;
fn normalize(input: &str) -> Cow<'_, str> {
if input.contains(' ') {
Cow::Owned(input.replace(' ', "_"))
} else {
Cow::Borrowed(input) // Zero-cost when no mutation needed
}
}
Result and ? — Never unwrap() in Production// Good: Propagate errors with context
use anyhow::{Context, Result};
fn load_config(path: &str) -> Result<Config> {
let content = std::fs::read_to_string(path)
.with_context(|| format!("failed to read config from {path}"))?;
let config: Config = toml::from_str(&content)
.with_context(|| format!("failed to parse config from {path}"))?;
Ok(config)
}
// Bad: Panics on error
fn load_config_bad(path: &str) -> Config {
let content = std::fs::read_to_string(path).unwrap(); // Panics!
toml::from_str(&content).unwrap()
}
thiserror, Application Errors with anyhow// Library code: structured, typed errors
use thiserror::Error;
#[derive(Debug, Error)]
pub enum StorageError {
#[error("record not found: {id}")]
NotFound { id: String },
#[error("connection failed")]
Connection(#[from] std::io::Error),
#[error("invalid data: {0}")]
InvalidData(String),
}
// Application code: flexible error handling
use anyhow::{bail, Result};
fn run() -> Result<()> {
let config = load_config("app.toml")?;
if config.workers == 0 {
bail!("worker count must be > 0");
}
Ok(())
}
Option Combinators Over Nested Matching// Good: Combinator chain
fn find_user_email(users: &[User], id: u64) -> Option<String> {
users.iter()
.find(|u| u.id == id)
.map(|u| u.email.clone())
}
// Bad: Deeply nested matching
fn find_user_email_bad(users: &[User], id: u64) -> Option<String> {
match users.iter().find(|u| u.id == id) {
Some(user) => match &user.email {
email => Some(email.clone()),
},
None => None,
}
}
// Good: Impossible states are unrepresentable
enum ConnectionState {
Disconnected,
Connecting { attempt: u32 },
Connected { session_id: String },
Failed { reason: String, retries: u32 },
}
fn handle(state: &ConnectionState) {
match state {
ConnectionState::Disconnected => connect(),
ConnectionState::Connecting { attempt } if *attempt > 3 => abort(),
ConnectionState::Connecting { .. } => wait(),
ConnectionState::Connected { session_id } => use_session(session_id),
…
通过双评审智能体对结果进行对抗式校验,提升输出发布前的可靠性
提供地道 Go 语言模式与最佳实践,帮助构建健壮高效且易维护的应用