rust-systems

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Rust Systems & Services

Rust系统与服务

Covers modern application-layer Rust (edition 2024): CLIs, web services, libraries. Not
no_std
/embedded.
涵盖现代应用层Rust(2024版本):CLI、Web服务、库。不包含
no_std
/嵌入式开发内容。

Tooling

工具链

ToolPurpose
cargo
Build, dep management, script runner
clippy
Lint (
cargo clippy --workspace --all-targets -- -D warnings
)
rustfmt
Formatter (
cargo fmt --all
)
cargo-nextest
Test runner
cargo-deny
License + advisory + duplicate-dep checks
cargo-machete
Find unused dependencies
  • Pin
    rust-toolchain.toml
    per repo so every contributor and CI uses the same compiler.
  • cargo update -p <crate>
    for single-package upgrades.
    cargo update
    rewrites everything — avoid in PR diffs.
  • Cargo.lock
    goes in version control for binaries and libraries (modern guidance; reproducibility wins).
工具用途
cargo
构建、依赖管理、脚本运行器
clippy
代码检查(
cargo clippy --workspace --all-targets -- -D warnings
rustfmt
代码格式化(
cargo fmt --all
cargo-nextest
测试运行器
cargo-deny
许可证、安全预警、重复依赖检查
cargo-machete
查找未使用的依赖
  • 每个仓库固定
    rust-toolchain.toml
    ,确保所有贡献者和CI使用相同版本的编译器。
  • 使用
    cargo update -p <crate>
    升级单个包。
    cargo update
    会更新所有依赖——在PR差异中避免使用该命令。
  • 二进制文件和库的
    Cargo.lock
    都应纳入版本控制(现代最佳实践;可复现性优先)。

Workspaces

工作区

Multi-crate projects use a workspace with layered crates. Dependencies point inward only.
Cargo.toml                  # [workspace] members + [workspace.dependencies]
crates/
  protocol/    # Shared types, no deps on other workspace crates
  storage/     # Persistence, depends on protocol
  service/    # Business logic, depends on protocol + storage
  cli/        # Binary, depends on everything
  • Centralize versions in
    [workspace.dependencies]
    , reference as
    foo = { workspace = true }
    in members.
  • Keep the leaf-most crate (
    protocol
    / types) dependency-free so every other crate can depend on it without cycles.
  • Feature flags belong on the crate that introduces the dependency, not re-exported through the workspace root.
  • Library crates expose one stable facade: a thin
    lib.rs
    with a
    //!
    purpose doc and
    pub use
    re-exports — one import path per concept, internals free to reorganize without breaking callers.
  • pub
    alone does not prove an item is externally reachable.
    Reachability runs through the re-export graph: a
    pub
    item inside a private module that is never re-exported is free to change, while the same item surfaced through a
    pub use
    at the crate root is not — even though its containing module stays private. (A
    pub(crate)
    item cannot be re-exported outside the crate:
    pub use
    on one is
    E0364
    , while
    pub(crate) use
    compiles.) Trace the facade before calling a reorganization internal. On a library crate with a published baseline,
    cargo semver-checks
    settles it mechanically.
  • Defining a
    macro_rules!
    or proc macro, or handling paths, process output, or on-disk state?
    Load macros-and-os-boundaries.md
    $crate
    resolution, single-interpolation of
    $x:expr
    ,
    $t:tt
    precedence, item-name collisions across invocations,
    syn::Error
    over panic, non-UTF-8
    Path
    /
    OsStr
    , and write-then-rename. These type-check cleanly and fail on a caller's machine.
  • Document public items at the point of exposure.
    ///
    on every public item (purpose, params, return, plus
    # Examples
    /
    # Errors
    /
    # Panics
    /
    # Safety
    where they apply);
    //!
    for modules and crates. Doc examples compile and run under
    cargo test --doc
    , so they are regression tests, not decoration. Enforce with
    #![deny(missing_docs)]
    on library crates; see rustdoc.md.
  • Feature gates must error, never silently degrade. If runtime config requests a capability the binary wasn't compiled with (e.g.
    device = "gpu"
    on a non-CUDA build), fail at startup — silent fallback diverges from operator config unnoticed.
  • Centralize lints at the workspace root with
    [workspace.lints.*]
    — every member crate inherits the same ruleset, no per-crate
    #![deny(...)]
    drift:
    toml
    [workspace.lints.clippy]
    all = { level = "warn", priority = -1 }
    pedantic = { level = "warn", priority = -1 }
    Each member crate opts in with
    [lints] workspace = true
    .
多crate项目使用分层crate的工作区,依赖仅向内引用。
Cargo.toml                  # [workspace]成员 + [workspace.dependencies]
crates/
  protocol/    # 共享类型,不依赖工作区中的其他crate
  storage/     # 持久化模块,依赖protocol
  service/    # 业务逻辑,依赖protocol + storage
  cli/        # 二进制程序,依赖所有模块
  • [workspace.dependencies]
    中集中管理版本,成员crate中通过
    foo = { workspace = true }
    引用。
  • 最底层的crate(
    protocol
    /类型模块)应无依赖,确保其他所有crate都能依赖它而不产生循环。
  • 特性标志应添加在引入依赖的crate上,而非通过工作区根目录重新导出。
  • 库crate需暴露一个稳定的对外接口:简洁的
    lib.rs
    包含
    //!
    用途文档和
    pub use
    重导出——每个概念对应一个导入路径,内部结构可自由调整而不破坏调用方代码。
  • pub
    修饰并不代表项可被外部访问
    。可访问性需通过重导出链判断:私有模块内的
    pub
    项若从未被重导出,则可自由修改;而通过crate根目录
    pub use
    暴露的同一项则不可修改——即使其所在模块仍为私有。(
    pub(crate)
    项无法被导出到crate外部:对其使用
    pub use
    会触发
    E0364
    错误,而
    pub(crate) use
    可正常编译。)在调整内部结构前,先追踪对外接口。对于已发布基线的库crate,可使用
    cargo semver-checks
    自动检查版本兼容性。
  • 定义
    macro_rules!
    或过程宏,或处理路径、进程输出、磁盘状态?
    参考macros-and-os-boundaries.md——包含
    $crate
    解析、
    $x:expr
    单次插值、
    $t:tt
    优先级、调用间的项名冲突、
    syn::Error
    替代panic、非UTF-8的
    Path
    /
    OsStr
    、先写后重命名等内容。这些内容可通过类型检查,且会在调用方机器上明确报错。
  • 在暴露点为公共项添加文档。每个公共项都需添加
    ///
    注释(说明用途、参数、返回值,必要时添加
    # Examples
    /
    # Errors
    /
    # Panics
    /
    # Safety
    );模块和crate需添加
    //!
    注释。文档示例可通过
    cargo test --doc
    编译运行,因此它们是回归测试而非装饰。在库crate中通过
    #![deny(missing_docs)]
    强制要求文档;参考rustdoc.md
  • 特性标志必须报错,而非静默降级。若运行时配置请求了二进制未编译的功能(例如非CUDA构建中设置
    device = "gpu"
    ),应在启动时失败——静默回退会导致实际行为与操作员配置不一致且未被察觉。
  • 在工作区根目录集中管理代码检查规则,通过
    [workspace.lints.*]
    配置——所有成员crate继承相同规则集,避免每个crate单独设置
    #![deny(...)]
    导致规则不一致:
    toml
    [workspace.lints.clippy]
    all = { level = "warn", priority = -1 }
    pedantic = { level = "warn", priority = -1 }
    每个成员crate通过
    [lints] workspace = true
    启用继承。

Build Profiles

构建配置文件

When tuning Cargo build profiles (release LTO, release-dbg symbols, release-min for distributable binaries) or adding dev-machine speedups (mold linker,
target-cpu=native
, share-generics), load build-profiles.md.
当调整Cargo构建配置文件(发布版本LTO、发布版本调试符号、用于分发二进制文件的最小化发布版本)或添加开发机器加速配置(mold链接器、
target-cpu=native
、共享泛型)时,参考build-profiles.md

Error Handling

错误处理

Split by crate role:
  • Libraries / lower crates: define typed errors with
    thiserror
    . Consumers can pattern-match.
  • Binaries / top-level crates: use
    anyhow::Result
    with
    .context("what was being attempted")
    . Human-readable error chains.
  • Never return
    Box<dyn Error>
    from library APIs — it erases variant information.
  • Use
    ?
    liberally. Never
    .unwrap()
    or
    .expect()
    outside tests and
    main
    . An
    expect("...")
    is acceptable only when the invariant is provably upheld and the message explains why.
  • Convert at boundaries:
    #[from]
    on thiserror variants for auto-conversion;
    .map_err(MyError::from)
    when explicit.
  • bail!("...")
    /
    ensure!(cond, "...")
    in application code for early exits.
  • Prefer
    Result<T, E>
    over panics for any recoverable error. Panics are for programmer bugs (broken invariants), not runtime failures.
  • #[must_use]
    on fallible APIs
    : annotate functions returning
    Result
    or newtype-wrapped results that callers frequently ignore. Catches
    let _ = validate(x);
    at compile time instead of shipping a silently-dropped error.
  • Make illegal call-sequences unrepresentable — the type-state pattern: encode a mandatory call order as distinct types (
    Client<Uninitialized>
    Client<Connected>
    ) so an out-of-order call fails to compile instead of erroring at runtime.
按crate角色划分:
  • 库/底层crate:使用
    thiserror
    定义类型化错误,便于消费者进行模式匹配。
  • 二进制程序/顶层crate:使用
    anyhow::Result
    并配合
    .context("当前操作描述")
    ,生成人类可读的错误链。
  • 库API绝不要返回
    Box<dyn Error>
    ——这会丢失变体信息。
  • 大量使用
    ?
    操作符。除测试和
    main
    函数外,绝不要使用
    .unwrap()
    .expect()
    。只有当不变量可被证明成立且注释说明原因时,
    expect("...")
    才是可接受的。
  • 在边界处转换错误:在thiserror变体上使用
    #[from]
    实现自动转换;需要显式转换时使用
    .map_err(MyError::from)
  • 在应用代码中使用
    bail!("...")
    /
    ensure!(cond, "...")
    实现提前退出。
  • 对于可恢复错误,优先使用
    Result<T, E>
    而非panic。panic仅用于程序员错误(破坏不变量),而非运行时故障。
  • 对易出错的API添加
    #[must_use]
    :对返回
    Result
    或调用方常忽略的新类型包装结果的函数添加该注解。在编译时捕获
    let _ = validate(x);
    这类代码,避免错误被静默丢弃。
  • 使非法调用序列无法被表示——类型状态模式:将强制调用顺序编码为不同类型(
    Client<Uninitialized>
    Client<Connected>
    ),使顺序错误的调用在编译阶段失败而非运行时报错。

Ownership Discipline

所有权规范

  • Take
    &str
    over
    &String
    ,
    &[T]
    over
    &Vec<T>
    in function signatures — accepts more call sites for free.
  • Return owned (
    String
    ,
    Vec<T>
    ) from constructors and public APIs. Borrow in hot paths where lifetimes are obvious.
  • Reach for
    Arc<T>
    only when sharing across threads. Single-threaded sharing uses
    Rc<T>
    or references.
  • Cow<'_, str>
    when a function sometimes allocates and sometimes borrows (e.g. normalization).
  • Rely on lifetime elision. More than one signature needing an explicit
    'a
    is a signal the type should own its data — convert the borrow to owned before adding lifetimes.
  • Reducing hot-path allocations (SmallVec, ArrayVec, string interning,
    Bytes
    , vectored writes): profile first, then load performance.md.
  • 函数签名中优先使用
    &str
    而非
    &String
    &[T]
    而非
    &Vec<T>
    ——可兼容更多调用场景。
  • 构造函数和公共API返回所有权类型(
    String
    Vec<T>
    )。在生命周期明确的热点路径中使用借用。
  • 仅在线程间共享数据时使用
    Arc<T>
    。单线程共享使用
    Rc<T>
    或引用。
  • 当函数有时需要分配内存、有时可借用数据时(例如归一化操作),使用
    Cow<'_, str>
  • 依赖生命周期省略规则。若多个签名需要显式
    'a
    ,则表明该类型应拥有自身数据——在添加生命周期前将借用转换为所有权类型。
  • 减少热点路径的内存分配(SmallVec、ArrayVec、字符串驻留、
    Bytes
    、向量写入):先进行性能分析,再参考performance.md

Async with Tokio

基于Tokio的异步编程

  • Default runtime:
    #[tokio::main]
    with
    features = ["full"]
    for apps;
    features = ["rt", "macros", "sync"]
    for libraries that need to stay slim.
  • tokio::spawn
    for independent tasks.
    JoinSet
    for a dynamic group awaited together with cancellation.
  • tokio::select!
    for racing futures (timeouts, cancellation, first-wins).
  • Never block the runtime:
    tokio::task::spawn_blocking
    for sync CPU work or blocking I/O libs.
  • tokio::sync::Mutex
    only when the guard must be held across
    .await
    . Otherwise
    std::sync::Mutex
    is faster.
  • tokio::sync::RwLock
    when reads dominate writes
    (config snapshots, route tables, hot caches). Many readers proceed in parallel;
    Mutex
    serializes them. For snapshot-swap semantics (rarely-updated config),
    arc-swap::ArcSwap
    is faster still — no lock on the read path.
  • Cancellation:
    CancellationToken
    (from
    tokio-util
    ) propagates shutdown. Long-running tasks must check it.
  • Backpressure via bounded
    mpsc
    channels — unbounded channels hide memory growth until OOM.
  • Semaphore
    for hard concurrency limits
    on spawn paths that don't fit a channel model (e.g. "at most 50 concurrent outbound HTTP calls").
    let _permit = sem.acquire().await?;
    inside the task; dropping the permit releases the slot. Pair with
    Arc<Semaphore>
    shared across spawners.
  • Don't mix async runtimes. Pick
    tokio
    and stick with it;
    async-std
    and
    smol
    don't interop cleanly.
  • 默认运行时:应用程序使用
    #[tokio::main]
    并启用
    features = ["full"]
    ;需保持轻量的库使用
    features = ["rt", "macros", "sync"]
  • 使用
    tokio::spawn
    创建独立任务。使用
    JoinSet
    管理动态任务组,可一起等待并支持取消。
  • 使用
    tokio::select!
    实现future竞争(超时、取消、先完成优先)。
  • 绝不要阻塞运行时:对于同步CPU密集型工作或阻塞I/O库,使用
    tokio::task::spawn_blocking
  • 仅当需要在
    .await
    期间持有锁时使用
    tokio::sync::Mutex
    。否则
    std::sync::Mutex
    速度更快。
  • 当读操作远多于写操作时使用
    tokio::sync::RwLock
    (配置快照、路由表、热点缓存)。多个读操作可并行执行;
    Mutex
    会序列化所有操作。对于快照交换语义(极少更新的配置),
    arc-swap::ArcSwap
    速度更快——读路径无锁。
  • 取消机制:使用
    CancellationToken
    (来自
    tokio-util
    )传播关闭信号。长时间运行的任务必须检查该信号。
  • 通过有界
    mpsc
    通道实现背压——无界通道会隐藏内存增长直至发生OOM。
  • 使用
    Semaphore
    实现硬并发限制
    ,适用于不适合通道模型的任务创建场景(例如“最多50个并发出站HTTP调用”)。在任务内部执行
    let _permit = sem.acquire().await?;
    ;释放permit会归还槽位。配合
    Arc<Semaphore>
    在多个任务创建者间共享。
  • 不要混合使用异步运行时。选择
    tokio
    并坚持使用;
    async-std
    smol
    无法良好互操作。

CLI Tools (clap)

CLI工具(clap)

  • Use the derive API:
    #[derive(Parser)]
    +
    #[derive(Subcommand)]
    . Less boilerplate, types drive the help text.
  • One
    enum Commands
    variant per subcommand; flatten shared flags into a
    #[command(flatten)] struct CommonArgs
    .
  • --json
    flag on query commands for agent/pipe consumption. Emit via
    serde_json::to_string(&value)?
    .
  • Exit codes: 0 success, 1 for errors
    main
    returned, 2 for argparse (clap handles this), reserve 3+ for domain meanings documented in
    --help
    .
  • Provide
    --version
    automatically via
    #[command(version)]
    .
See cli-tools.md for config layering, logging setup, progress reporting, and shell completions.
  • 使用派生API:
    #[derive(Parser)]
    +
    #[derive(Subcommand)]
    。更少样板代码,类型驱动帮助文本生成。
  • 每个子命令对应一个
    enum Commands
    变体;将共享标志整合到
    #[command(flatten)] struct CommonArgs
    中。
  • 查询命令添加
    --json
    标志,便于Agent/管道消费。通过
    serde_json::to_string(&value)?
    输出。
  • 退出码:0表示成功,1表示
    main
    返回的错误,2表示参数解析错误(clap自动处理),3及以上保留给领域特定含义并在
    --help
    中说明。
  • 通过
    #[command(version)]
    自动提供
    --version
    功能。
参考cli-tools.md了解配置分层、日志设置、进度报告和Shell补全。

HTTP Services (axum)

HTTP服务(axum)

  • Framework default: axum (tokio-native, tower middleware, extractor-based handlers). Pick
    actix-web
    only if an existing codebase uses it.
  • Handlers return
    Result<impl IntoResponse, AppError>
    . Implement
    IntoResponse
    for
    AppError
    to centralize error → status mapping.
  • Validate input at the boundary:
    axum::extract::Json<T>
    where
    T: Deserialize + Validate
    (use
    validator
    crate). Internal services trust input was validated.
  • Share state via
    State<Arc<AppState>>
    — not globals, not
    lazy_static
    .
  • Middleware via
    tower::ServiceBuilder
    : tracing → timeout → auth → CORS → handler. Order matters.
  • Resilience layers (outbound clients, shared services): combine
    LoadShed
    +
    ConcurrencyLimit
    for backpressure, not unbounded queueing; full tower stack in production-resilience.md.
See axum-service.md for project layout, extractors, error types, graceful shutdown, and OpenAPI generation.
  • 默认框架:axum(基于tokio、tower中间件、提取器式处理器)。仅当现有代码库使用
    actix-web
    时才选择它。
  • 处理器返回
    Result<impl IntoResponse, AppError>
    。为
    AppError
    实现
    IntoResponse
    以集中处理错误→状态码映射。
  • 在边界处验证输入:使用
    axum::extract::Json<T>
    ,其中
    T: Deserialize + Validate
    (使用
    validator
    crate)。内部服务信任输入已被验证。
  • 通过
    State<Arc<AppState>>
    共享状态——不使用全局变量或
    lazy_static
  • 通过
    tower::ServiceBuilder
    添加中间件:tracing → 超时 → 认证 → CORS → 处理器。顺序至关重要。
  • 弹性层(出站客户端、共享服务):结合
    LoadShed
    +
    ConcurrencyLimit
    实现背压,避免无界排队;完整的tower栈参考production-resilience.md
参考axum-service.md了解项目布局、提取器、错误类型、优雅关闭和OpenAPI生成。

Concurrency

并发

WorkloadApproach
Independent async I/O
tokio::spawn
+
JoinSet
or
futures::join!
Data-parallel CPU work
rayon
with
par_iter
Shared mutable state across threads
Arc<Mutex<T>>
or
Arc<RwLock<T>>
, smallest scope possible
Single-producer pipelines
tokio::sync::mpsc
(async) or
std::sync::mpsc
(sync)
Broadcast / fan-out
tokio::sync::broadcast
rayon
and
tokio
coexist — use
tokio::task::spawn_blocking
to call a rayon pool from async code. Never call
.block_on()
from inside a tokio task; it deadlocks the runtime.
工作负载实现方式
独立异步I/O
tokio::spawn
+
JoinSet
futures::join!
数据并行CPU工作
rayon
配合
par_iter
线程间共享可变状态
Arc<Mutex<T>>
Arc<RwLock<T>>
,尽可能缩小作用域
单生产者流水线
tokio::sync::mpsc
(异步)或
std::sync::mpsc
(同步)
广播/扇出
tokio::sync::broadcast
rayon
tokio
可共存——使用
tokio::task::spawn_blocking
从异步代码中调用rayon池。绝不要在tokio任务内部调用
.block_on()
;这会导致运行时死锁。

Testing

测试

  • Built-in
    #[test]
    . Prefer
    cargo nextest run --workspace
    over
    cargo test
    — it runs tests in parallel processes with proper isolation.
  • Unit tests live in
    mod tests { ... }
    at the bottom of the file (access to private items).
  • Integration tests in
    tests/
    directory. One file per public surface area.
  • #[tokio::test]
    for async tests. Add
    flavor = "multi_thread"
    when the code under test spawns tasks.
  • rstest
    for parametrized tests and fixtures.
    proptest
    /
    quickcheck
    for property-based tests on pure logic.
  • insta
    for snapshot testing CLI output, serialization, large structs. Review diffs with
    cargo insta review
    .
  • assert_cmd
    +
    predicates
    for CLI integration tests (invokes the binary, asserts on stdout/stderr/exit code).
  • Assert on error variants with
    matches!
    :
    assert!(matches!(result.unwrap_err(), MyError::Validation(_)))
    — no
    match
    arms to update when unrelated variants are added.
  • Coverage:
    cargo llvm-cov --workspace --html
    . Target 70%+ on application code, higher on library crates.
  • Fuzzing for parsers:
    cargo fuzz
    +
    libfuzzer-sys
    on any code parsing untrusted input; nightly runs surface panics and UB unit tests miss.
For generic test discipline (anti-patterns, mock rules, rationalization resistance), see the
ia-writing-tests
skill.
  • 使用内置的
    #[test]
    。优先使用
    cargo nextest run --workspace
    而非
    cargo test
    ——它在并行进程中运行测试并提供适当的隔离。
  • 单元测试放在文件底部的
    mod tests { ... }
    中(可访问私有项)。
  • 集成测试放在
    tests/
    目录中,每个文件对应一个公共接口。
  • 异步测试使用
    #[tokio::test]
    。当被测代码会创建任务时,添加
    flavor = "multi_thread"
  • 使用
    rstest
    实现参数化测试和夹具。使用
    proptest
    /
    quickcheck
    对纯逻辑进行基于属性的测试。
  • 使用
    insta
    进行快照测试,适用于CLI输出、序列化、大型结构体。使用
    cargo insta review
    查看差异。
  • 使用
    assert_cmd
    +
    predicates
    进行CLI集成测试(调用二进制程序,断言标准输出/标准错误/退出码)。
  • 使用
    matches!
    断言错误变体
    assert!(matches!(result.unwrap_err(), MyError::Validation(_)))
    ——添加无关变体时无需更新match分支。
  • 覆盖率:
    cargo llvm-cov --workspace --html
    。应用代码目标覆盖率70%+,库crate目标覆盖率更高。
  • 解析器模糊测试:对处理非可信输入的代码使用
    cargo fuzz
    +
    libfuzzer-sys
    ;nightly版本运行可发现单元测试遗漏的panic和UB。
通用测试规范(反模式、mock规则、抗合理化)参考
ia-writing-tests
技能。

Unsafe Discipline

Unsafe代码规范

  • Default: no
    unsafe
    . If clippy flags it, don't
    #[allow]
    it — refactor. The
    #[expect]
    escape hatch below does not apply here; unsafe findings get fixed, not annotated.
  • Every
    unsafe
    block gets a
    // SAFETY:
    comment above it explaining why each invariant holds. No comment = reviewer rejects.
  • Keep
    unsafe
    blocks minimal — wrap in a safe abstraction at module boundary, mark the module
    pub(crate)
    .
  • Use
    miri
    (
    cargo +nightly miri test
    ) on any crate containing
    unsafe
    or raw pointer arithmetic — catches UB that optimizers mask.
  • Prefer
    bytemuck
    ,
    zerocopy
    ,
    bytes
    over hand-rolled transmutes for zero-copy patterns.
  • Env-var writes are
    unsafe
    in edition 2024. Write them only in
    main
    , before the runtime starts or any thread spawns.
    Concurrent
    getenv
    is UB;
    OnceLock
    does not make it safe. Watch for lazy
    LD_LIBRARY_PATH
    -style writes on first use — hoist them to startup.
  • 默认:不使用
    unsafe
    。若clippy标记了问题,不要使用
    #[allow]
    ——重构代码。下面的
    #[expect]
    逃生舱不适用于此;unsafe代码问题必须修复,而非注解。
  • 每个
    unsafe
    块上方必须添加
    // SAFETY:
    注释,说明每个不变量成立的原因。无注释则评审者应拒绝。
  • 尽可能缩小
    unsafe
    块的范围——在模块边界处包装为安全抽象,并将模块标记为
    pub(crate)
  • 对包含
    unsafe
    或原始指针算术的crate使用
    miri
    cargo +nightly miri test
    )——捕获优化器掩盖的UB。
  • 对于零拷贝模式,优先使用
    bytemuck
    zerocopy
    bytes
    而非手动实现transmute。
  • 在2024版本中,写入环境变量是
    unsafe
    操作。仅在
    main
    函数中写入,且需在运行时启动或任何线程创建之前完成。
    并发
    getenv
    是UB;
    OnceLock
    无法使其安全。注意首次使用时延迟写入
    LD_LIBRARY_PATH
    这类环境变量——将其提前到启动阶段。

Production Resilience

生产环境弹性

When productionizing a service (config validation,
/health
+
/ready
endpoints, graceful shutdown, retries/timeouts/jitter, deny-by-default fallback when the call is the security decision, connection pools, diagnostic secret redaction), load production-resilience.md.
当将服务投入生产环境时(配置验证、
/health
+
/ready
端点、优雅关闭、重试/超时/抖动、调用时默认拒绝的安全决策、连接池、诊断信息脱敏),参考production-resilience.md

Observability

可观测性

For logging (
tracing
+
tracing-subscriber
with init recipe),
#[instrument]
spans, correlation IDs, metrics, and distributed tracing patterns, load observability.md. Never use
println!
or
log::
in new code.
日志(
tracing
+
tracing-subscriber
初始化方案)、
#[instrument]
跨度、关联ID、指标和分布式追踪模式参考observability.md。新代码中绝不要使用
println!
log::

CI

CI

General CI design lives with the
ia-infrastructure-engineer
agent. For Rust-specific callouts (
rustsec/audit-check
,
cargo-llvm-cov
,
Swatinem/rust-cache
,
taiki-e/install-action
, matrix coverage guidance, doc-test step), load ci-pipeline.md.
通用CI设计参考
ia-infrastructure-engineer
Agent。Rust特定注意事项(
rustsec/audit-check
cargo-llvm-cov
Swatinem/rust-cache
taiki-e/install-action
、矩阵覆盖率指导、文档测试步骤)参考ci-pipeline.md

Discipline

开发规范

  • Simplicity first — every change as simple as possible, impact minimal code.
  • Only touch what's necessary — avoid unrelated changes in a PR.
  • No
    #[allow(clippy::...)]
    as a shortcut — fix the underlying issue. When a suppression is genuinely warranted, write
    #[expect(clippy::lint_name, reason = "...")]
    instead:
    expect
    warns once the lint stops firing, so a suppression that has outlived its cause reports itself, where
    allow
    rots silently forever. (
    expect
    needs Rust 1.81+; edition 2024 clears that floor.)
  • Before adding a trait or generic, verify it's used in 3+ places. Otherwise a concrete type is clearer.
  • 优先保持简洁——每个变更尽可能简单,影响代码范围最小。
  • 仅修改必要内容——避免在PR中包含无关变更。
  • 不要使用
    #[allow(clippy::...)]
    走捷径——修复根本问题。当确实需要抑制时,使用
    #[expect(clippy::lint_name, reason = "...")]
    替代:
    expect
    会在规则不再触发时发出警告,因此失效的抑制会自动报告,而
    allow
    会静默失效。(
    expect
    需要Rust 1.81+;2024版本满足该要求。)
  • 在添加 trait 或泛型之前,确认其已在3个以上场景中使用。否则具体类型更清晰。

Verify

验证

  • cargo fmt --all -- --check
    passes with zero diffs
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
    passes
  • cargo nextest run --workspace
    (or
    cargo test --workspace
    ) passes with zero failures
  • cargo deny check
    passes (licenses, advisories, duplicates) for any crate going to production
  • No new
    unsafe
    without
    // SAFETY:
    comment
  • cargo fmt --all -- --check
    通过,无差异
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
    通过
  • cargo nextest run --workspace
    (或
    cargo test --workspace
    )通过,无失败
  • 投入生产环境的crate需通过
    cargo deny check
    (许可证、安全预警、重复依赖)
  • 新增
    unsafe
    代码必须带有
    // SAFETY:
    注释