Rust 模块与 Crate

这是系列最后一篇,讲 Rust 如何组织大型项目的代码。前面所有概念(函数、结构体、枚举、Trait)都在单个文件里讲,真实项目会有几十上百个文件。Crate、Package、Module 是 Rust 的代码组织系统,理解它才能写出可维护的大型项目。

1. 概念层次:Crate / Package / Module

这三个概念从大到小,新手容易混。理清它们:

// Rust 代码组织系统的几个概念,从大到小:

// 1. Crate(木箱):Rust 的【编译单元】
//    分两种:
//      - binary crate(可执行程序):有 main 函数
//      - library crate(库):供其他 crate 引用,有 lib.rs

// 2. Package(包):一个 Cargo 项目
//    包含一个 Cargo.toml + src/ 目录
//    一个 package 可以同时包含 binary 和 library

// 3. Module(模块):crate 内部的代码组织
//    用 mod 关键字声明,形成树形结构

// 例:一个典型的项目结构
// my_app/                     <- package
// ├── Cargo.toml
// ├── src/
// │   ├── main.rs             <- binary crate 的根
// │   ├── lib.rs              <- library crate 的根(可选)
// │   ├── network/            <- 模块目录
// │   │   ├── mod.rs          <- 模块声明
// │   │   ├── server.rs
// │   │   └── client.rs
// │   └── utils.rs            <- 单文件模块
// └── tests/

层次关系:

2. mod 声明模块

mod 关键字声明模块。Rust 会按约定找对应的文件:

// src/main.rs 或 src/lib.rs

// 声明模块:mod 关键字
// Rust 会去找对应的文件:
//   mod network;  -> src/network.rs 或 src/network/mod.rs
mod network;
mod utils;

fn main() {
    // 用路径访问模块里的内容
    // 完整路径:crate::network::server::start()
    network::server::start();
    utils::helper();
}

// 内联模块:直接在文件里写
mod math {
    // pub 表示公开(模块外可见)
    // 默认是私有(只能在当前模块及子模块访问)
    pub fn add(a: i32, b: i32) -> i32 {
        a + b
    }

    fn secret() -> i32 {        // 私有,模块外不能用
        42
    }

    // 嵌套子模块
    pub mod geometry {
        pub fn area(r: f64) -> f64 {
            3.14 * r * r
        }
    }
}

fn use_math() {
    // 完整路径访问
    let sum = math::add(1, 2);
    let a = math::geometry::area(5.0);
}

模块文件查找规则(Rust 2018 之后):

可见性:默认一切都是私有的。要让模块外能访问,加 pub。这是 Rust 的安全设计——不主动暴露内部实现。

3. use 导入路径

use 把长路径"导入"到当前作用域,避免每次写全路径:

mod network;

// use:把路径"导入"到当前作用域,简化引用
use network::server;            // 之后可以直接写 server::start()
use network::server::start;     // 直接导入函数

fn main() {
    server::start();            // 不用写 network:: 前缀
    start();                     // 直接调用

    // 嵌套路径一次导入多个
    use network::{server, client};
    server::start();
    client::connect();

    // 用 as 重命名(避免命名冲突)
    use network::server as srv;
    srv::start();

    // 通配 * 导入全部(谨慎用,易污染命名空间)
    // use network::*;
}

// 标准库的 prelude:Rust 自动导入一批最常用项
// 如 Vec、String、Option、Result、Vec、Box 等
// 不需要 use 就能用,因为它们在 prelude 里

几个技巧:

4. pub 可见性

Rust 的可见性规则:默认私有,显式 pub 公开。这是封装的基石:

// 可见性规则:默认一切都是私有的!
// pub 关键字让项公开

// 文件结构:
// src/network/mod.rs
pub mod server;            // 公开子模块(让外部能 use network::server)
pub mod client;

mod internal;              // 私有子模块(只在 network 内部用)

pub fn connect() {         // 公开函数
    // ...
}

fn helper() {              // 私有函数
    // ...
}

// 结构体的可见性:字段默认私有
pub struct User {
    pub name: String,      // 公开字段
    age: u32,              // 私有字段(模块外不能直接访问)
}

// 枚举:一旦枚举 pub,所有变体都公开
pub enum Color {
    Red, Green, Blue,      // 全部公开
}

// 三种路径前缀:
// crate::xxx     从当前 crate 根开始(绝对路径)
// self::xxx      从当前模块开始
// super::xxx     上一级模块(类似 ../ )
// ::xxx          外部 crate 或标准库

关键点:

5. 引用第三方 Crate

Rust 的官方 crate 仓库叫 crates.io,所有开源库都在那里。用 Cargo 添加依赖:

// Cargo.toml
// [dependencies]
// rand = "0.8"               # 引入第三方库 rand
// serde = { version = "1", features = ["derive"] }

// 在代码里 use 外部 crate
use rand::Rng;

fn main() {
    let mut rng = rand::thread_rng();
    let n: i32 = rng.gen_range(1..=100);   // 1-100 随机数
    println!("随机数: {}", n);
}

// 添加依赖的几种方式:
// 1. cargo add rand          # 自动写入 Cargo.toml 并下载
// 2. 手动编辑 Cargo.toml
// 3. cargo add rand@0.8      # 指定版本

// 版本号语法(SemVer):
// "1.2.3"   精确版本
// "1.2"     允许 1.2.x
// "1"       允许 1.x.x
// "^1.2.3"  允许 1.x.x(默认,和 "1" 类似)
// "=1.2.3"  精确版本
// "*"       任意版本(危险!)

常用操作:

Rust 的生态远比想象丰富:Web 框架(axum, actix-web)、序列化(serde)、数据库(sqlx, diesel)、异步(tokio)、HTTP(reqwest, hyper)、命令行(clap)……几乎所有需求都有成熟的 crate。

6. 标准库 std

标准库 std 是 Rust 自带的,不需要在 Cargo.toml 声明,直接 use 即可。它提供基础数据结构和 IO:

use std::collections::HashMap;
use std::fs;
use std::io::Read;

fn main() {
    // std 是 Rust 标准库,无需在 Cargo.toml 声明
    // 直接 use 即可

    // 常用标准库模块:
    // std::collections   - HashMap, HashSet, BTreeMap, VecDeque
    // std::fs            - 文件操作
    // std::io            - 输入输出
    // std::net           - 网络编程
    // std::thread        - 多线程
    // std::sync          - 同步原语(Mutex, Arc, RwLock)
    // std::time          - 时间(Duration, Instant)
    // std::env           - 环境变量、命令行参数
    // std::process       - 进程控制
    // std::path          - 路径处理(跨平台)

    let mut map = HashMap::new();
    map.insert("apple", 3);
    map.insert("banana", 5);
    println!("{:?}", map);

    // 读取环境变量
    if let Ok(name) = std::env::var("USER") {
        println!("用户: {}", name);
    }
}

标准库的核心模块:

7. 实战项目结构示例

看一个典型的中型应用如何组织模块:

// 项目结构示例:一个完整应用的模块组织

// src/main.rs
mod config;         // 引入 config.rs
mod db;             // 引入 db/mod.rs
mod api;            // 引入 api/mod.rs
mod utils;          // 引入 utils.rs

use config::Config;
use db::Database;

fn main() {
    let cfg = Config::load();
    let db = Database::new(&cfg.db_url);
    api::serve(db);
}

// src/config.rs
pub struct Config { /* ... */ }
impl Config {
    pub fn load() -> Config { /* ... */ }
}

// src/db/mod.rs
pub mod models;
pub mod queries;

pub struct Database { /* ... */ }

// src/api/mod.rs
pub fn serve(db: db::Database) { /* ... */ }

// 这种组织让代码可维护,不同关注点分到不同模块

组织原则:

8. workspace(多 crate 项目)

大型项目可能有多个相关 crate(如一个核心库 + 多个工具)。Cargo workspace 让多个 crate 共享同一个 Cargo.lock 和 target 目录:

这是 Rust 大型项目(如 Rust 编译器自身、tokio)的标准组织方式。

9. 文档注释与 cargo doc

Rust 的文档注释(///)会被 cargo doc 生成漂亮的 HTML 文档站点。这是工程化的亮点:

小结

这一篇你掌握了 Rust 的代码组织系统:Crate(编译单元,binary/library)、Package(Cargo 项目)、Module(mod 声明)、use(导入路径)、pub(可见性)、第三方 crate(crates.io + cargo add)、workspace(多 crate 项目)。这套系统让你能组织任意大的 Rust 项目,同时保持模块化和封装。

系列总结

恭喜!你完成了 Rust 16 篇入门系列。回顾这段旅程:从环境安装到所有权、借用,再到结构体、枚举、Trait、错误处理、模块系统——你已经掌握了 Rust 的全部核心概念。

Rust 的入门确实比 Python 难,你一定在所有权和借用那里撞过墙——这是所有Rust 学习者的必经之路。但跨过这道墙后,你得到的回报是:极少 bug 的代码、极致的性能、以及一种全新的编程思维方式。

下一步建议:

Rust 连续多年"最受喜爱"不是没有理由。慢慢来,值得。祝你在 Rust 的旅程中收获满满!

← 上一篇 Rust 错误处理

返回 Rust 教程目录

✈️💬