blog.dopana

Back

当 Rust 项目规模逐渐超出单个源码文件时,良好的代码组织与作用域管理至关重要。Rust 提供了严谨的模块系统,兼顾封装性、隐私安全与可复用性。

像给 10 岁孩子解释:玩具工厂与作业部门#

把构建一个 Rust 项目想象成运营一家大型玩具工厂:

  1. Package (Cargo.toml): 整个工厂园区,包含建造图纸、工具箱和采购清单。
  2. Crate (包 / 箱): 装满组装好的产品、可以直接交付给客户或合作伙伴的集装箱(可执行程序或共享库)。
  3. Module (部门): 工厂内部各个独立作业车间(如:木工车间、喷漆车间、质检部门)。
  4. 访问隐私 (pub): 内部工作车间的防盗门(private)与对外开放的接待前台(pub)。Rust 默认将所有房门锁上,防止外部误入操作精密机器。
graph TD
    subgraph Package ["Package (Cargo.toml)"]
        subgraph BinaryCrate ["Binary Crate (src/main.rs)"]
            MainFn["main() entry point"]
        end
        subgraph LibraryCrate ["Library Crate (src/lib.rs)"]
            RootMod["Crate Root (crate::)"]
            RootMod --> ModFront["mod front_of_house"]
            ModFront --> ModHosting["pub mod hosting"]
            ModHosting --> FnAdd["pub fn add_to_waitlist()"]
            RootMod --> ModBack["mod back_of_house"]
            ModBack --> FnCook["fn fix_incorrect_order()"]
        end
    end
    MainFn -->|use restaurant::front_of_house::hosting| FnAdd

核心概念层级#

概念定义文件组织约定
Package包含 Cargo.toml 的 Cargo 构建单元,用于构建一个或多个 Crate。包含 Cargo.toml 的项目根目录
Crate生成二进制可执行文件或库文件的模块树编译单元。src/main.rs (二进制) 或 src/lib.rs (库)
Module组织 Crate 内部代码结构并控制访问权限的命名空间。内联 mod name { ... }src/name.rs
Path引用模块树中各项内容(结构体、函数等)的定位路径。crate::front_of_house::hosting::add_to_waitlist()

模块与隐私规则#

在 Rust 中,所有项(函数、方法、结构体、枚举、模块)默认对父模块完全私有(private)。

graph LR
    Parent["父模块"] -->|可见子模块的所有内容| Child["子模块"]
    Child -->|不可见未公开的同级项| Sibling["同级项"]
    Child -->|始终可见父模块中的项| Parent

餐厅业务模块实例#

[!NOTE] 将模块声明为 pub mod 仅代表父级可以引用该模块本身。其内部的函数和字段仍为私有,必须逐个添加 pub 显式导出。

结构体与枚举在 pub 下的区别#

pub 在结构体和枚举中的表现有所不同:

  • 结构体 (Struct): 使用 pub struct 仅公开结构体类型名称,其内部字段仍默认为私有,必须逐个为公开字段添加 pub
  • 枚举 (Enum): 一旦使用 pub enum,其包含的所有枚举成员(Variants)将自动全部公开。

使用 use 将路径引入作用域#

重复编写冗长路径会导致代码繁琐。使用 use 关键字可像创建软链接一样将路径引入当前作用域:

sequenceDiagram
    participant Code as 调用方代码
    participant Scope as 本地作用域
    participant CrateTree as Crate 模块树

    Note over Scope,CrateTree: use crate::front_of_house::hosting;
    Scope->>CrateTree: 解析 hosting 模块路径
    CrateTree-->>Scope: 在当前作用域创建 hosting 别名
    Code->>Scope: hosting::add_to_waitlist()
    Scope->>CrateTree: 最终调用 front_of_house::hosting::add_to_waitlist()

使用 pub use 重新导出接口#

使用 use 引入的项在当前作用域默认为私有。结合使用 pub use 可以将其对外公开,从而设计出优雅扁平的公开 API:

src/lib.rs
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

// 重新导出:外部用户可以直接调用 restaurant::hosting::add_to_waitlist()
pub use crate::front_of_house::hosting;
rust

将模块拆分为独立多文件#

在工程化开发中,推荐将模块映射到独立的文件与目录结构:

my_project/
├── Cargo.toml
└── src/
    ├── main.rs
    ├── lib.rs
    └── front_of_house/
        ├── mod.rs (或 front_of_house.rs)
        └── hosting.rs
text
src/lib.rs
// 声明 front_of_house 模块,Rust 会自动定位并加载 src/front_of_house.rs
pub mod front_of_house;

pub use crate::front_of_house::hosting;
rust
src/front_of_house.rs
// 声明 hosting 子模块,Rust 会自动加载 src/front_of_house/hosting.rs
pub mod hosting;
rust
src/front_of_house/hosting.rs
pub fn add_to_waitlist() {
    println!("已成功添加至等候列表!");
}
rust

总结#

  • Package 是由 Cargo.toml 统一管理的 Crate 集合。
  • Crate 是生成二进制或共享库的编译基本单元。
  • Module (mod) 构建树状命名空间并控制可见性。
  • Rust 默认私有;使用 pub 精确暴露模块、函数和字段。
  • 使用 use 简化调用路径,使用 pub use 优雅重构公开 API。

参考资料#