mcpField
R
rust-systems

rust-systems

github.com/rohitg00开发2.8k185 次安装24 周前更新
代码仓库

关于 rust-systems

面向 Rust 开发者的系统编程技能指南,涵盖所有权、错误处理、Trait、异步模式、配置构建与常见问题。

主要功能

  1. 01所有权与借用指导
  2. 02使用 thiserror 和 anyhow 处理错误
  3. 03Trait 与泛型
  4. 04有界异步并发
  5. 05配置的构建器模式
  6. 06反模式与检查清单

适用场景

  1. 01检查 Rust 代码中的不必要克隆
  2. 02设计库和应用的错误类型
  3. 03实现有界并发的异步任务

安装

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

$npx skills add https://github.com/rohitg00/awesome-claude-code-toolkit --skill rust-systems

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

详细介绍

Rust 系统编程

所有权与借用

fn process_data(data: &[u8]) -> Vec<u8> {
    data.iter().map(|b| b.wrapping_add(1)).collect()
}

fn modify_in_place(data: &mut Vec<u8>) {
    data.retain(|b| *b != 0);
    data.sort_unstable();
}

fn take_ownership(data: Vec<u8>) -> Vec<u8> {
    let mut result = data;
    result.push(0xFF);
    result
}

fn main() {
    let data = vec![1, 2, 3, 0, 4];
    let processed = process_data(&data);     // borrow: data still usable
    let mut owned = take_ownership(data);     // move: data no longer usable
    modify_in_place(&mut owned);              // mutable borrow
}

优先使用借用(&T、&mut T),而非转移所有权。仅在必要时使用 Clone。

错误处理

use thiserror::Error;

#[derive(Error, Debug)]
pub enum AppError {
    #[error("database error: {0}")]
    Database(#[from] sqlx::Error),

    #[error("not found: {resource} with id {id}")]
    NotFound { resource: &'static str, id: String },

    #[error("validation failed: {0}")]
    Validation(String),
}

type Result<T> = std::result::Result<T, AppError>;

async fn get_user(pool: &PgPool, id: &str) -> Result<User> {
    sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = $1")
        .bind(id)
        .fetch_optional(pool)
        .await?
        .ok_or_else(|| AppError::NotFound {
            resource: "User",
            id: id.to_string(),
        })
}

库错误使用 thiserror,应用级错误使用 anyhow。避免在生产代码中使用 .unwrap()。

Trait 与泛型

trait Repository {
    type Item;
    type Error;

    async fn find_by_id(&self, id: &str) -> std::result::Result<Option<Self::Item>, Self::Error>;
    async fn save(&self, item: &Self::Item) -> std::result::Result<(), Self::Error>;
}

struct PgUserRepo {
    pool: PgPool,
}

impl Repository for PgUserRepo {
    type Item = User;
    type Error = AppError;

    async fn find_by_id(&self, id: &str) -> Result<Option<User>> {
        let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = $1")
            .bind(id)
            .fetch_optional(&self.pool)
            .await?;
        Ok(user)
    }

    async fn save(&self, user: &User) -> Result<()> {
        sqlx::query("INSERT INTO users (id, name, email) VALUES ($1, $2, $3)")
            .bind(&user.id)
            .bind(&user.name)
            .bind(&user.email)
            .execute(&self.pool)
            .await?;
        Ok(())
    }
}

异步模式

use tokio::sync::Semaphore;
use futures::stream::{self, StreamExt};

async fn fetch_all(urls: Vec<String>, max_concurrent: usize) -> Vec<Result<String>> {
    let semaphore = Arc::new(Semaphore::new(max_concurrent));

    stream::iter(urls)
        .map(|url| {
            let sem = semaphore.clone();
            async move {
                let _permit = sem.acquire().await.unwrap();
                reqwest::get(&url).await?.text().await.map_err(Into::into)
            }
        })
        .buffer_unordered(max_concurrent)
        .collect()
        .await
}

async fn graceful_shutdown(handle: tokio::runtime::Handle) {
    let ctrl_c = tokio::signal::ctrl_c();
    ctrl_c.await.expect("Failed to listen for Ctrl+C");
    handle.shutdown_timeout(std::time::Duration::from_secs(30));
}

构建器模式

pub struct ServerConfig {
    host: String,
    port: u16,
    workers: usize,
    tls: bool,
}

pub struct ServerConfigBuilder {
    host: String,
    port: u16,
    workers: usize,
    tls: bool,
}

impl ServerConfigBuilder {
    pub fn new() -> Self {
        Self { host: "0.0.0.0".into(), port: 8080, workers: 4, tls: false }
    }

    pub fn host(mut self, host: impl Into<String>) -> Self { self.host = host.into(); self }
    pub fn port(mut self, port: u16) -> Self { self.port = port; self }
    pub fn workers(mut self, n: usize) -> Self { self.workers = n; self }
    pub fn tls(mut self, enabled: bool) -> Self { self.tls = enabled; self }

    pub fn build(self) -> ServerConfig {
        ServerConfig { host: self.host, port: self.port, workers: self.workers, tls: self.tls }
    }
}

反模式

  • 在库代码中使用 .unwrap() 或 .expect()
  • 不必要地克隆数据,而不使用借用
  • 在 .await 处持有 MutexGuard(会导致死锁)
  • 在通道更合适时使用 Arc<Mutex<Vec<T>>>
  • 编写 unsafe 代码却不记录不变量
  • 未在返回 Result 的函数上使用 #[must_use]

检查清单

  • 使用 thiserror 定义错误类型,并使用 ? 运算符传播错误
  • 生产代码路径中没有 .unwrap()
  • 所有权模型尽量减少克隆
  • 异步代码使用有界并发(信号量或 buffer_unordered)
  • 使用 Trait 实现抽象并提升可测试性
  • unsafe 代码块记录了安全不变量
  • 复杂配置结构体使用构建器模式
  • 启用了 Clippy lint 并处理了警告

评论

支持 Markdown