首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >05-Rust 教程 - 模块系统

05-Rust 教程 - 模块系统

作者头像
LarryLan
发布2026-03-30 18:08:42
发布2026-03-30 18:08:42
330
举报

Rust 教程 - 模块系统

模块系统:代码界的"收纳术",让混乱变秩序


🎬 引入

想象一下,你的代码文件越来越长,从 100 行到 500 行,再到 1000 行...最后打开文件,好家伙,滚轮都滚不到底。找个函数得用 Ctrl+F,改个变量得小心翼翼怕重名。

这时候你就需要模块系统了。模块就像是你家的收纳柜:衣服放衣柜,书放书架,厨房用品放橱柜。找东西时,直接去对应的柜子拿,不用翻箱倒柜。

Rust 的模块系统被很多人吐槽"复杂",但一旦你搞懂了,就会发现它其实很有逻辑。今天咱们就来拆解这个"复杂"的系统,让你从此不再迷路。


📌 核心概念

模块是什么?

模块(Module)就是代码的组织单元。它帮你:

  • 把相关代码放在一起
  • 避免命名冲突
  • 控制代码的可见性(谁能用,谁不能用)

生活化类比

  • Package(包) = 整个项目(比如一个完整的 APP)
  • Crate(箱)" = 编译单元(一个库或一个可执行程序)
  • Module(模块) = 文件夹/章节(代码的内部组织)

Crate:Rust 的"编译单元"

Crate 是 Rust 编译的最小单元。有两种:

  • 二进制 Crate:可执行程序,必须有 main 函数
  • 库 Crate:供别人调用的库,没有 main 函数
代码语言:javascript
复制
// src/main.rs - 二进制 crate
fn main() {
    println!("我是可执行程序!");
}

// src/lib.rs - 库 crate
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

Package:Crate 的"包装盒"

Package 是 Cargo 管理的单位,一个 Package 可以包含:

  • 最多一个库 Crate
  • 任意多个二进制 Crate

判断方法:看 Cargo.toml 文件。有 [package] 就是 Package。

代码语言:javascript
复制
# Cargo.toml
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"

# 这是一个 Package

Module:用 mod 声明

模块用 mod 关键字声明。有两种方式:

方式 1:内联模块(适合小模块)

代码语言:javascript
复制
mod garden {
    fn plant() {
        println!("种花🌸");
    }
}

方式 2:文件模块(适合大模块)

代码语言:javascript
复制
// src/main.rs
mod garden;  // Rust 会去找 src/garden.rs 或 src/garden/mod.rs

// src/garden.rs
fn plant() {
    println!("种花🌸");
}

路径:找到你的代码

Rust 用路径来定位模块里的东西,就像文件系统的 /home/user/file.txt

路径类型

语法

说明

绝对路径

crate::module::item

从 crate 根开始

相对路径

self::item 或 super::item

从当前模块开始

使用声明

use crate::module::item

引入到当前作用域

代码语言:javascript
复制
// 绝对路径
crate::garden::plant();

// 相对路径(当前模块)
self::plant();

// 相对路径(父模块)
super::other_function();

可见性:pub 关键字

默认情况下,模块里的东西都是私有的(只有自己模块能用)。想让外面用?加 pub

代码语言:javascript
复制
// src/lib.rs
pub mod utils {
    pub fn helper() {  // 外部可以调用
        println!("我是公共函数");
    }
    
    fn internal() {  // 外部不能调用
        println!("我是私有函数");
    }
}

// src/main.rs
use my_lib::utils;

fn main() {
    utils::helper();    // ✅ 可以
    utils::internal();  // ❌ 编译错误
}

可见性层级

  • pub - 完全公开
  • pub(crate) - 整个 crate 内可见
  • pub(super) - 父模块可见
  • pub(in path) - 指定路径可见

use:引入模块

use 关键字用来把模块里的东西"引入"到当前作用域,这样就不用写长长的路径了。

代码语言:javascript
复制
// 不使用 use
fn main() {
    std::collections::HashMap::new();
    std::collections::HashMap::new();
    std::collections::HashMap::new();
}

// 使用 use
use std::collections::HashMap;

fn main() {
    HashMap::new();
    HashMap::new();
    HashMap::new();
}

use 的骚操作

代码语言:javascript
复制
// 引入多个
use std::collections::{HashMap, HashSet};

// 重命名(避免冲突)
use std::fmt::Result as FmtResult;
use std::io::Result as IoResult;

// 引入所有(慎用!)
use std::collections::*;

// 嵌套路径
use std::{collections::HashMap, io::Write};

💻 代码示例

基础示例:一个简单的模块结构

代码语言:javascript
复制
// src/main.rs
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {
            println!("已加入等候名单");
        }
        
        pub fn seat_at_table() -> String {
            String::from("table 1")
        }
    }
    
    mod serving {
        fn take_order() {}
        fn serve_order() {}
    }
}

fn main() {
    // 使用绝对路径
    front_of_house::hosting::add_to_waitlist();
    
    // 使用 use 引入
    use front_of_house::hosting;
    hosting::seat_at_table();
}

错误示例 1:私有模块无法访问

代码语言:javascript
复制
// src/main.rs
mod front_of_house {
    mod hosting {  // 没有 pub!
        pub fn add_to_waitlist() {}
    }
}

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

编译器错误

代码语言:javascript
复制
error[E0603]: module `hosting` is private
 --> src/main.rs:9:21
  |
9 |     front_of_house::hosting::add_to_waitlist();
  |                     ^^^^^^^ private module
  |
note: the module `hosting` is defined here
 --> src/main.rs:3:5
  |
3 |     mod hosting {
  |     ^^^^^^^^^^^

人话翻译:编译器:"hosting 模块是私有的,外面不让进!想让人家用,加个 pub 啊!"

错误示例 2:路径错误

代码语言:javascript
复制
// src/main.rs
mod garden {
    fn plant() {}
}

fn main() {
    plant();  // 错了!plant 在 garden 模块里
}

编译器错误

代码语言:javascript
复制
error[E0425]: cannot find function `plant` in this scope
 --> src/main.rs:8:5
  |
8 |     plant();
  |     ^^^^^ not found in this scope
  |
help: consider importing this function
  |
1 | use crate::garden::plant;
  |

人话翻译:编译器:"plant 不在这里!它在 garden 模块里。要么写全路径 garden::plant(),要么用 use 引进来。"

错误示例 3:循环依赖

代码语言:javascript
复制
// src/a.rs
use crate::b::func_b;

pub fn func_a() {
    func_b();
}

// src/b.rs
use crate::a::func_a;

pub fn func_b() {
    func_a();  // 编译错误:循环依赖
}

编译器错误

代码语言:javascript
复制
error[E0423]: expected function, found module
 --> src/b.rs:6:5
  |
6 |     func_a();
  |     ^^^^^^ not a function

人话翻译:编译器:"你俩互相调用,是想把我绕晕吗?重构一下代码结构吧!"


🐛 常见坑点

坑点 1:忘记 pub

代码语言:javascript
复制
mod utils {
    fn helper() {}  // 私有
}

fn main() {
    utils::helper();  // 编译错误
}

修复:加 pub

代码语言:javascript
复制
mod utils {
    pub fn helper() {}  // 公开
}

坑点 2:文件模块放错位置

代码语言:javascript
复制
// src/main.rs
mod garden;  // Rust 会找 src/garden.rs

// 但你把文件放到了 src/modules/garden.rs ❌

修复:文件要放在正确位置。

代码语言:javascript
复制
src/
├── main.rs
├── garden.rs  ✅ 正确
└── modules/
    └── garden.rs  ❌ 错误

坑点 3:use 引入后还是用错

代码语言:javascript
复制
use crate::front_of_house::hosting;

fn main() {
    hosting::add_to_waitlist();  // ✅ 对
    front_of_house::hosting::add_to_waitlist();  // ✅ 也对
}

记住:use 只是引入别名,原来的路径还能用。

坑点 4:super 用晕了

代码语言:javascript
复制
mod front {
    mod hosting {
        fn add_to_waitlist() {
            super::serve();  // 指向 front 模块
        }
    }
    
    fn serve() {}
}

记忆技巧

  • self = 当前目录(.
  • super = 上一级目录(..
  • crate = 项目根目录(/

🎯 实战案例

案例 1:组织一个完整的库

代码语言:javascript
复制
// src/lib.rs
pub mod calculator {
    pub mod arithmetic {
        pub fn add(a: i32, b: i32) -> i32 { a + b }
        pub fn subtract(a: i32, b: i32) -> i32 { a - b }
        pub fn multiply(a: i32, b: i32) -> i32 { a * b }
        pub fn divide(a: i32, b: i32) -> Option<i32> {
            if b ==  { None } else { Some(a / b) }
        }
    }
    
    pub mod statistics {
        pub fn average(nums: &[i32]) -> f64 {
            let sum: i32 = nums.iter().sum();
            sum as f64 / nums.len() as f64
        }
    }
}

// src/main.rs
use my_lib::calculator::arithmetic;
use my_lib::calculator::statistics;

fn main() {
    let sum = arithmetic::add(, );
    let avg = statistics::average(&[, , , , ]);
    println!("和:{}, 平均:{}", sum, avg);
}

案例 2:用文件模块组织代码

代码语言:javascript
复制
my_project/
├── Cargo.toml
└── src/
    ├── main.rs
    ├── models.rs
    ├── views.rs
    └── controllers.rs
代码语言:javascript
复制
// src/main.rs
mod models;
mod views;
mod controllers;

use controllers::handle_request;

fn main() {
    handle_request();
}

// src/models.rs
pub struct User {
    pub name: String,
    pub age: u32,
}

// src/views.rs
use crate::models::User;

pub fn render_user(user: &User) {
    println!("用户:{}, 年龄:{}", user.name, user.age);
}

// src/controllers.rs
use crate::models::User;
use crate::views::render_user;

pub fn handle_request() {
    let user = User {
        name: String::from("Alice"),
        age: ,
    };
    render_user(&user);
}

案例 3:use 的最佳实践

代码语言:javascript
复制
// ❌ 不推荐:引入所有
use std::*;

// ✅ 推荐:明确引入
use std::collections::HashMap;
use std::io::{self, Write};

// ✅ 推荐:重命名避免冲突
use std::result::Result as StdResult;
use my_lib::Result;

🧠 思维导图

05-模块系统
05-模块系统

📝 小结

  1. Package 是 Cargo 单位,Crate 是编译单位,Module 是代码组织单位
  2. 默认私有,公开加 pub——这是 Rust 的封装哲学
  3. 路径分绝对和相对crate:: 从头开始,self:: 当前,super:: 父级
  4. use 引入到当前作用域,可以重命名避免冲突
  5. 文件模块放对位置mod foo 对应 src/foo.rssrc/foo/mod.rs

下篇预告:模块里放什么?函数?数据?下一篇咱们聊聊结构体,看看 Rust 怎么组织数据!


🔗 参考资料

  • Rust Book - 模块系统
  • Rust By Example - 模块
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-03-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Larry的Hub 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Rust 教程 - 模块系统
    • 🎬 引入
    • 📌 核心概念
      • 模块是什么?
      • Crate:Rust 的"编译单元"
      • Package:Crate 的"包装盒"
      • Module:用 mod 声明
      • 路径:找到你的代码
      • 可见性:pub 关键字
      • use:引入模块
    • 💻 代码示例
      • 基础示例:一个简单的模块结构
      • 错误示例 1:私有模块无法访问
      • 错误示例 2:路径错误
      • 错误示例 3:循环依赖
    • 🐛 常见坑点
      • 坑点 1:忘记 pub
      • 坑点 2:文件模块放错位置
      • 坑点 3:use 引入后还是用错
      • 坑点 4:super 用晕了
    • 🎯 实战案例
      • 案例 1:组织一个完整的库
      • 案例 2:用文件模块组织代码
      • 案例 3:use 的最佳实践
    • 🧠 思维导图
    • 📝 小结
    • 🔗 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档