概述

Rust 的模块系统提供了组织代码的强大工具。通过模块、包和 crate,你可以将代码组织成可重用、可维护的结构。

包(Package)和 Crate

包和 Crate 的关系

  • 包(Package):用于构建、测试和共享 crate 的 Cargo 功能

  • Crate:一个模块树,它产生一个库或可执行文件

  • 模块(Module):使用 mod 关键字定义的代码组织单元

创建包

cargo new my_project

这会创建以下结构:

my_project/
├── Cargo.toml
└── src/
    └── main.rs

包的规则

  1. 一个包必须包含 0 个或 1 个库 crate

  2. 可以包含任意数量的二进制 crate

  3. 至少包含一个 crate(库或二进制)

定义模块

基本 mod 关键字

mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}
        fn seat_at_table() {}
    }
    
    mod serving {
        fn take_order() {}
        fn serve_order() {}
        fn take_payment() {}
    }
}

模块树

crate
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment

路径

绝对路径

mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}
    }
}

pub fn eat_at_restaurant() {
    // 绝对路径
    crate::front_of_house::hosting::add_to_waitlist();
}

相对路径

mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}
    }
}

pub fn eat_at_restaurant() {
    // 相对路径
    front_of_house::hosting::add_to_waitlist();
}

使用 super 访问父模块

fn serve_order() {}

mod back_of_house {
    fn fix_incorrect_order() {
        cook_order();
        super::serve_order();
    }
    
    fn cook_order() {}
}

公开模块

pub 关键字

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

pub fn eat_at_restaurant() {
    // 现在可以访问了
    front_of_house::hosting::add_to_waitlist();
}

结构体的可见性

mod back_of_house {
    pub struct Breakfast {
        pub toast: String,
        seasonal_fruit: String,  // 私有字段
    }
    
    impl Breakfast {
        pub fn summer(toast: &str) -> Breakfast {
            Breakfast {
                toast: String::from(toast),
                seasonal_fruit: String::from("桃子"),
            }
        }
    }
}

pub fn eat_at_restaurant() {
    // 可以创建实例
    let mut meal = back_of_house::Breakfast::summer("黑麦");
    
    // 可以访问公共字段
    meal.toast = String::from("小麦");
    
    // 不能访问私有字段
    // meal.seasonal_fruit = String::from("蓝莓");
}

枚举的可见性

mod back_of_house {
    pub enum Appetizer {
        Soup,
        Salad,
    }
}

pub fn eat_at_restaurant() {
    let order1 = back_of_house::Appetizer::Soup;
    let order2 = back_of_house::Appetizer::Salad;
}

使用 use 关键字

导入路径

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

导入函数与结构体

// 导入函数(习惯上使用父模块)
use std::collections::HashMap;

// 导入结构体(习惯上直接导入)
use std::collections::HashMap;

// 导入枚举(习惯上直接导入)
use std::collections::HashMap;

使用 as 提供别名

use std::fmt::Result;
use std::io::Result as IoResult;

fn function1() -> Result {
    Ok(())
}

fn function2() -> IoResult<()> {
    Ok(())
}

重新导出

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

使用嵌套路径

use std::cmp::Ordering;
use std::io;

// 等价于:
use std::{cmp::Ordering, io};

使用 glob 运算符

use std::collections::*;

将模块拆分到不同文件

基本文件结构

src/
├── main.rs
└── front_of_house/
    ├── mod.rs
    ├── hosting.rs
    └── serving.rs

front_of_house/mod.rs

pub mod hosting;
pub mod serving;

front_of_house/hosting.rs

pub fn add_to_waitlist() {}

front_of_house/serving.rs

pub fn take_order() {}

main.rs

mod front_of_house;

use front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

使用外部包

添加依赖

Cargo.toml 中添加:

[dependencies]
rand = "0.8.5"

使用外部包

use rand::Rng;

fn main() {
    let secret_number = rand::thread_rng().gen_range(1..=100);
    println!("随机数: {}", secret_number);
}

常用外部包

[dependencies]
serde = "1.0"           # 序列化/反序列化
serde_json = "1.0"      # JSON 支持
tokio = { version = "1.0", features = ["full"] }  # 异步运行时
reqwest = { version = "0.11", features = ["json"] }  # HTTP 客户端
clap = "3.0"            # 命令行参数解析
log = "0.4"             # 日志门面
env_logger = "0.9"      # 日志实现

二进制和库 Crate

项目结构

my_project/
├── Cargo.toml
└── src/
    ├── main.rs          # 二进制 crate
    └── lib.rs           # 库 crate

lib.rs

pub mod front_of_house;

pub use front_of_house::hosting;

main.rs

use my_project::hosting;

fn main() {
    hosting::add_to_waitlist();
}

多个二进制文件

my_project/
├── Cargo.toml
└── src/
    ├── main.rs
    ├── lib.rs
    └── bin/
        ├── extra1.rs
        └── extra2.rs

工作空间(Workspace)

创建工作空间

my_workspace/
├── Cargo.toml
├── src/
│   └── main.rs
├── adder/
│   ├── Cargo.toml
│   └── src/
│       └── lib.rs
└── add-one/
    ├── Cargo.toml
    └── src/
        └── lib.rs

Cargo.toml(工作空间)

[workspace]
members = [
    "adder",
    "add-one",
]

adder/Cargo.toml

[package]
name = "adder"
version = "0.1.0"
edition = "2021"

[dependencies]
add-one = { path = "../add-one" }

adder/src/lib.rs

pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

pub fn add_two(a: i32) -> i32 {
    add_one::add_one(a) + 1
}

add-one/Cargo.toml

[package]
name = "add-one"
version = "0.1.0"
edition = "2021"

[dependencies]
rand = "0.8.5"

add-one/src/lib.rs

pub fn add_one(x: i32) -> i32 {
    x + 1
}

实际应用示例

创建一个简单的库

my_lib/
├── Cargo.toml
└── src/
    ├── lib.rs
    ├── math.rs
    └── string.rs

Cargo.toml

[package]
name = "my_lib"
version = "0.1.0"
edition = "2021"

[dependencies]

src/lib.rs

pub mod math;
pub mod string;

pub use math::add;
pub use string::reverse;

src/math.rs

pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

pub fn subtract(a: i32, b: i32) -> i32 {
    a - b
}

src/string.rs

pub fn reverse(s: &str) -> String {
    s.chars().rev().collect()
}

pub fn to_uppercase(s: &str) -> String {
    s.to_uppercase()
}

使用库

[dependencies]
my_lib = { path = "../my_lib" }
use my_lib::{add, reverse};

fn main() {
    let sum = add(5, 3);
    println!("5 + 3 = {}", sum);
    
    let reversed = reverse("hello");
    println!("反转后的字符串: {}", reversed);
}

总结

本教程详细介绍了 Rust 的模块与包管理:

  1. 包和 Crate

    • 包是 Cargo 的功能
    • Crate 是模块树
    • 一个包可以包含多个 crate
  2. 模块系统

    • 使用 mod 关键字定义模块
    • 模块树结构
    • 绝对路径和相对路径
  3. 可见性

    • 使用 pub 关键字公开模块
    • 结构体和枚举的可见性规则
    • 使用 super 访问父模块
  4. use 关键字

    • 导入路径
    • 提供别名
    • 重新导出
    • 嵌套路径和 glob 运算符
  5. 文件组织

    • 将模块拆分到不同文件
    • 模块文件命名约定
  6. 外部包

    • 添加依赖
    • 使用外部包
    • 常用外部包介绍
  7. 工作空间

    • 创建工作空间
    • 管理多个相关包

Rust 的模块系统提供了强大的代码组织能力,合理使用模块和包可以让代码更加清晰、可维护和可重用。

下一步

在下一教程中,我们将学习 Rust 的特质(Trait),这是 Rust 中定义共享行为的重要方式。我们将了解:

  • 定义和使用特质

  • 特质边界

  • 默认实现

  • 特质对象

  • 关联类型

继续学习 Rust,掌握这门强大语言的更多特性!