模块系统
随着项目规模增长,你需要组织代码。Rust 提供了模块系统来管理代码的作用域和可见性。
包与 Crate
Section titled “包与 Crate”- 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
使用 mod 关键字
Section titled “使用 mod 关键字”在 src/lib.rs 或 src/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路径用于引用模块中的项。
绝对路径与相对路径
Section titled “绝对路径与相对路径”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 关键字
Section titled “super 关键字”super 从父模块开始构建路径:
fn serve_order() {}
mod back_of_house { fn fix_incorrect_order() { cook_order(); super::serve_order(); // 调用父模块的函数 }
fn cook_order() {}}self 关键字
Section titled “self 关键字”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 关键字
Section titled “pub 关键字”使用 pub 公开项:
mod front_of_house { pub mod hosting { // 模块公开 pub fn add_to_waitlist() {} // 函数公开 }}结构体的可见性
Section titled “结构体的可见性”结构体字段默认私有:
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"); // 错误!私有字段}枚举的可见性
Section titled “枚举的可见性”枚举的变体默认与枚举本身可见性相同:
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 关键字
Section titled “use 关键字”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};glob 运算符
Section titled “glob 运算符”引入所有公开项:
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() {}}目录形式模块
Section titled “目录形式模块”文件结构:
src/├── lib.rs├── front_of_house/│ ├── mod.rs # 或 front_of_house.rs(新风格)│ └── hosting.rssrc/front_of_house/mod.rs(或 src/front_of_house.rs):
pub mod hosting;src/front_of_house/hosting.rs:
pub fn add_to_waitlist() {}两种文件组织风格
Section titled “两种文件组织风格”风格 1(传统):
src/front_of_house/mod.rs风格 2(推荐,Rust 2018+):
src/front_of_house.rs # 模块声明src/front_of_house/ # 子模块目录 hosting.rs两种风格不能混用。
实际项目结构示例
Section titled “实际项目结构示例”my_project/├── Cargo.toml├── src/│ ├── main.rs│ ├── lib.rs│ ├── config.rs│ ├── db/│ │ ├── mod.rs│ │ ├── connection.rs│ │ └── queries.rs│ └── api/│ ├── mod.rs│ ├── handlers.rs│ └── routes.rssrc/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::*;练习 1:创建模块
Section titled “练习 1:创建模块”创建一个库项目,包含 math 模块,内有 add 和 multiply 函数:
mod math { // 你的代码}
pub fn calculate() { // 使用 math 模块中的函数}练习 2:嵌套模块
Section titled “练习 2:嵌套模块”在 math 模块内创建子模块 advanced,包含 power 函数:
mod math { pub mod advanced { // 你的代码 }
pub fn add(a: i32, b: i32) -> i32 { // 你的代码 }}练习 3:重导出
Section titled “练习 3:重导出”使用 pub use 将深层模块的函数重导出到顶层:
mod math { pub mod advanced { pub fn power(base: i32, exp: u32) -> i32 { base.pow(exp) } }}
// 重导出,使外部可以直接使用 crate::powerpub use math::advanced::power;练习 4:文件组织
Section titled “练习 4:文件组织”将以下模块拆分到独立文件:
src/├── lib.rs├── math.rs└── math/ └── advanced.rssrc/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 中定义共享行为的方式。