记录一些学习 rust 中的非语法问题
常来说 每个语言都有专门的工作流,用这个语言编写某个项目/功能时,需要遵循一定的规范,这里做一点记录。
换源
自动
使用 chsrc 进行换源,详见上一篇工具
手动
在 $HOME/.cargo/config.toml 中
[source.crates-io]
replace-with = 'mirror'
[source.mirror]
registry = "sparse+https://mirrors.bfsu.edu.cn/crates.io-index/"三方库
- crates.io
官方支持的 rust 注册三方库 - lib.rs
我没用过 更好的分类不同库与更好的搜索
- docs.rs
官方文档托管 - github / google / 等 直接搜索
- Awesome Rust
社区维护的优秀 rust 三方库
对于一些固定的功能来说 三方库的选择几乎是固定的,例如:
解析 JSON:序列化与反序列 serde_json
随机数:rand
异步:tokio
错误处理:thiserror anyhow
日志:log tracing
等
我对三方库的积累还不够多 欢迎补充
查找三方库与其他语言类似 使用人数 维护状态 社区与依赖(对于 rust 来说 需要额外看unsafe 代码块多不多) 编译速度 等
对于一个项目来说 首先需要确定“大件”,也就是对核心功能做技术选型
例如 web 服务器 axum, actix-web, rocket
数据库 sqlx, diesel
一些常用命令
cargo test # 放在 #[cfg(test)] 宏 或者在 tests/ 中的测试代码
cargo build --release
cargo run
cargo doc # 在代码中进行文档注释(///) 后 能为函数与结构体自动编写文档
cargo clippy # rust 自带的 linter 能检查很多引用与实现问题
cargo check # 快速检查代码问题 不 build 就可以看到代码能不能成功 build
cargo fmt # 代码格式化工具
cargo add # 添加三方库
Cargo.toml
[dependencies]: 你所有的第三方库(称为 "crates")都在这里声明。
[dev-dependencies]: cargo test 或者 cargo bench 才会被编译,例如我在测试中加入了额外的错误处理anyhow,但代码中没有使用
[dependencies]
# 我需要 serde 的 1.0 版本,只需要他的 derive 功能
serde = { version = "1.0", features = ["derive"] }
[dev-dependencies]
anyhow = "1.0"cargo 自动生成 Cargo.lock 文件 会锁定项目使用的版本
[workspace] 管理多个 crates
还没接触到
思想
rust 的所有权与生命周期思想与其他 C like 的不太一样,有的在 C like 中很简单的代码在 rust 中非常复杂,例如链表
C/C++:你持有原始指针,你告诉编译器:“相信我,我知道我在做什么。”
Java/Python:你持有引用,GC(垃圾回收器)在背后帮你处理生命周期。
Rust:你必须在编译期就向编译器证明你的所有权和借用是 100% 安全的。编译器不“相信”你,它只“验证”你。
Result 与 Option 另一个重大的思想转变是错误处理。Rust 没有 try...catch 异常,也没有 null。
可能会失败的操作,返回 Result<T, E> (成功或错误)。
可能没有值的操作,返回 Option (有值或无值)。 这种方式强迫你在编译时就必须显式处理所有可能的失败路径,极大地提高了代码的健壮性。
编译器
rust 编译器是我见过的错误信息最完善的编译器,他会将问题具体指出,并给出一个可能的修复方案(有时候不是很准)
在ai时代,这无疑非常方便于 ai coding agent,尽管在 benchmark 中 各类 ai 对于 rust 支持并非 python 或者 java 这么完善,但有编译器详细的报错信息,在一轮代码输出错误的情况下,很快就能自行修复
错误处理
.unwrap() 或 .expect() 操作比较危险,需要保证不会错误 一般来说 使用操作符 ? 来自动管理 Result
文档
/// 将两个数相加。
///
/// # Examples
///
/// ```
/// let result = my_crate::add(2, 2);
/// assert_eq!(result, 4);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}顶上的///部分就是文档注释,在文档注释中的```代码块就是测试用例 在cargo test中会被执行
//! 是整个项目或者模块的注释 用来介绍项目或者模块是干什么的
git hook
脚本版
#!/bin/sh
echo "Running pre-commit hook..."
# 1. 检查格式化
echo "Checking formatting (cargo fmt)..."
cargo fmt -- --check
if [ $? -ne 0 ]; then
echo "Error: Code is not formatted. Run 'cargo fmt' and re-commit."
exit 1
fi
# 2. 检查 Clippy Lints (将所有警告视为错误)
echo "Checking lints (cargo clippy)..."
cargo clippy --all-targets -- -D warnings
if [ $? -ne 0 ]; then
echo "Error: Clippy found issues. Fix them and re-commit."
exit 1
fi
# 3. 运行测试
echo "Running tests (cargo test)..."
cargo test
if [ $? -ne 0 ]; then
echo "Error: Tests failed. Fix them and re-commit."
exit 1
fi
echo "All checks passed. Committing..."
exit 0不要忘了给可执行权限
chmod +x
pre-commit版
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-toml # 检查 Cargo.toml 语法
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: local
hooks:
- id: rust-fmt
name: rust-fmt
entry: cargo fmt --all -- --check
language: system
types: [rust]
pass_filenames: false
- id: rust-clippy
name: rust-clippy
entry: cargo clippy --all-targets -- -D warnings
language: system
types: [rust]
pass_filenames: false
- id: rust-test
name: rust-test
entry: cargo test
language: system
types: [rust]
pass_filenames: falsegithub ci 版
name: Rust CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build_and_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- name: Check formatting
run: cargo fmt --all -- --check
- name: Check lints
run: cargo clippy --all-targets -- -D warnings
- name: Run tests
run: cargo test