Skip to content

模块系统

随着项目规模增长,你需要组织代码。Rust 提供了模块系统来管理代码的作用域和可见性。

  • Crate:编译的最小单位,可以是二进制或库
  • Package:一个或多个 Crate 的集合,包含 Cargo.toml
  • Module:在 Crate 内组织代码的方式
my_project/
├── Cargo.toml
├── src/
│ ├── main.rs # 二进制 crate 入口
│ ├── lib.rs # 库 crate 入口
│ └── bin/
│ └── other.rs # 额外的二进制 crate

规则:

  • src/main.rs:二进制 crate 的根,crate 名与包名相同
  • src/lib.rs:库 crate 的根,crate 名与包名相同
  • 一个包最多一个库 crate,可以有多个二进制 crate

src/lib.rssrc/main.rs 中:

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 {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// 绝对路径(从 crate 根开始)
crate::front_of_house::hosting::add_to_waitlist();
// 相对路径(从当前模块开始)
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() {}
}

self 指当前模块:

mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use self::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}

默认情况下,所有项都是私有的。

使用 pub 公开项:

mod front_of_house {
pub mod hosting { // 模块公开
pub fn 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("peaches"),
}
}
}
}
pub fn eat_at_restaurant() {
let mut meal = back_of_house::Breakfast::summer("Rye");
meal.toast = String::from("Wheat"); // OK
// meal.seasonal_fruit = String::from("blueberries"); // 错误!私有字段
}

枚举的变体默认与枚举本身可见性相同:

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 front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
// 对于函数:引入父模块
use front_of_house::hosting;
hosting::add_to_waitlist();
// 对于结构体、枚举:引入完整路径
use std::collections::HashMap;
let mut map = HashMap::new();

使用 as 重命名:

use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result {
// --snip--
Ok(())
}
fn function2() -> IoResult<()> {
// --snip--
Ok(())
}

或者只引入父模块:

use std::fmt;
use std::io;
fn function1() -> fmt::Result { Ok(()) }
fn function2() -> io::Result<()> { Ok(()) }

使用 pub use 重导出:

mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
// 重导出,外部代码可以使用 hosting::add_to_waitlist()
pub use front_of_house::hosting;
// 分开写
use std::cmp::Ordering;
use std::io;
// 合并写
use std::{cmp::Ordering, io};
// 引入模块和其中的项
use std::io::{self, Write};

引入所有公开项:

use std::collections::*;

通常用于测试或 prelude 模式,日常代码不推荐。

src/lib.rs 中:

mod front_of_house; // 声明模块
pub use front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}

src/front_of_house.rs 中:

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

文件结构:

src/
├── lib.rs
├── front_of_house/
│ ├── mod.rs # 或 front_of_house.rs(新风格)
│ └── hosting.rs

src/front_of_house/mod.rs(或 src/front_of_house.rs):

pub mod hosting;

src/front_of_house/hosting.rs

pub fn add_to_waitlist() {}

风格 1(传统)

src/front_of_house/mod.rs

风格 2(推荐,Rust 2018+)

src/front_of_house.rs # 模块声明
src/front_of_house/ # 子模块目录
hosting.rs

两种风格不能混用。

my_project/
├── Cargo.toml
├── src/
│ ├── main.rs
│ ├── lib.rs
│ ├── config.rs
│ ├── db/
│ │ ├── mod.rs
│ │ ├── connection.rs
│ │ └── queries.rs
│ └── api/
│ ├── mod.rs
│ ├── handlers.rs
│ └── routes.rs

src/lib.rs

pub mod config;
pub mod db;
pub mod api;

src/db/mod.rs

pub mod connection;
pub mod queries;
pub use connection::connect;
pub use queries::*;

创建一个库项目,包含 math 模块,内有 addmultiply 函数:

src/lib.rs
mod math {
// 你的代码
}
pub fn calculate() {
// 使用 math 模块中的函数
}

math 模块内创建子模块 advanced,包含 power 函数:

mod math {
pub mod advanced {
// 你的代码
}
pub fn add(a: i32, b: i32) -> i32 {
// 你的代码
}
}

使用 pub use 将深层模块的函数重导出到顶层:

mod math {
pub mod advanced {
pub fn power(base: i32, exp: u32) -> i32 {
base.pow(exp)
}
}
}
// 重导出,使外部可以直接使用 crate::power
pub use math::advanced::power;

将以下模块拆分到独立文件:

src/
├── lib.rs
├── math.rs
└── math/
└── advanced.rs

src/lib.rs:

pub mod math;
pub use math::add;
pub use math::advanced::power;

src/math.rs:

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

src/math/advanced.rs:

pub fn power(base: i32, exp: u32) -> i32 {
base.pow(exp)
}

完成入门基础后,我们将进入进阶主题。下一章将学习 Trait——Rust 中定义共享行为的方式。