mcpField
R
rust-best-practices

rust-best-practices

github.com/majiayu000开发29089 次安装3 天前更新
代码仓库

关于 rust-best-practices

面向 Rust 开发者的实践指南,汇总 Microsoft Pragmatic Rust Guidelines 与 Rust 社区标准,涵盖错误处理、API 设计和类型系统使用。

主要功能

  1. 01类型系统与所有权实践
  2. 02显式错误处理建议
  3. 03库与应用的错误处理选择
  4. 04Builder 与 Newtype API 设计
  5. 05迭代器、泛型与 Trait 用法

适用场景

  1. 01设计 Rust 库的公共 API
  2. 02为应用选择错误处理方式
  3. 03检查代码中的 panic 风险

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/majiayu000/spellbook --skill rust-best-practices

安装后在 Claude Code 中输入/rust-best-practices确认已加载。

附带文件references/advanced.md

详细介绍

Rust 最佳实践

基于 Microsoft Pragmatic Rust Guidelines 和 Rust 社区标准。

核心原则

  1. 善用类型系统 — 使用类型让无效状态无法表示
  2. 拥抱所有权 — 与借用检查器协作,而不是对抗它
  3. 明确胜于隐式 — 清晰说明可失败性、可变性和生命周期
  4. 零成本抽象 — 使用迭代器、泛型和 trait,且不产生运行时开销
  5. 快速失败,优雅恢复 — 尽早验证,明确处理错误

错误处理

库使用 thiserror
use thiserror::Error;

#[derive(Error, Debug)]
pub enum MyError {
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
    #[error("Parse error at line {line}: {message}")]
    Parse { line: usize, message: String },
    #[error("Not found: {0}")]
    NotFound(String),
}
应用使用 anyhow
use anyhow::{Context, Result};

fn main() -> Result<()> {
    let config = load_config()
        .context("Failed to load configuration")?;
    run_app(config)?;
    Ok(())
}
库中绝不使用 panic
// ❌ BAD
pub fn get_item(index: usize) -> &Item {
    &self.items[index]  // Panics on out-of-bounds
}

// ✅ GOOD
pub fn get_item(&self, index: usize) -> Option<&Item> {
    self.items.get(index)
}

// ✅ GOOD - when you need Result
pub fn get_item(&self, index: usize) -> Result<&Item, Error> {
    self.items.get(index).ok_or(Error::NotFound(index))
}

API 设计

复杂配置使用 Builder 模式
pub struct Client {
    url: String,
    timeout: Duration,
    retries: u32,
}

impl Client {
    pub fn builder(url: impl Into<String>) -> ClientBuilder {
        ClientBuilder {
            url: url.into(),
            timeout: Duration::from_secs(30),
            retries: 3,
        }
    }
}

pub struct ClientBuilder {
    url: String,
    timeout: Duration,
    retries: u32,
}

impl ClientBuilder {
    pub fn timeout(mut self, timeout: Duration) -> Self {
        self.timeout = timeout;
        self
    }

    pub fn retries(mut self, retries: u32) -> Self {
        self.retries = retries;
        self
    }

    pub fn build(self) -> Client {
        Client {
            url: self.url,
            timeout: self.timeout,
            retries: self.retries,
        }
    }
}
使用 Newtype 模式
// ❌ BAD - primitive obsession
fn create_user(name: String, email: String, age: u32) -> User { ... }

// ✅ GOOD - newtype wrappers
pub struct Username(String);
pub struct Email(String);
pub struct Age(u32);

impl Email {
    pub fn new(email: impl Into<String>) -> Result<Self, ValidationError> {
        let email = email.into();
        if email.contains('@') {
            Ok(Self(email))
        } else {
            Err(ValidationError::InvalidEmail)
        }
    }
}

fn create_user(name: Username, email: Email, age: Age) -> User { ... }
接受 impl Trait 以提高灵活性
// ❌ BAD - overly specific
pub fn process(items: Vec<String>) { ... }

// ✅ GOOD - accept any iterable
pub fn process(items: impl IntoIterator<Item = impl AsRef<str>>) {
    for item in items {
        println!("{}", item.as_ref());
    }
}

参考资料

评论

支持 Markdown