Rust 模块系统:mod、可见性与路径
更新时间:2026-09-20。Rust 用模块树组织代码、用可见性控制边界,即使单文件也能定义模块;而真正的编译与包边界由 cargo 约定决定。工程拆分与
cargo模型见 Cargo 与编译模型。
一、模块是一棵树
crate(一个库或可执行文件)的模块从根文件开始:库 crate 根是 src/lib.rs,二进制 crate 根是 src/main.rs。
rust
// src/lib.rs
mod network { // 内联模块
pub fn connect() {}
mod internal { // 嵌套子模块
pub fn secret() {}
}
}
pub use network::connect; // 重导出,外部可 crate_name::connect文件模块与目录的对应(cargo 约定,Rust 2018+):
bash
src/lib.rs
src/network.rs // mod network; 的内容
src/network/mod.rs // 旧写法(2015),仍兼容
src/network/client.rs // network 的子模块 client在父模块里声明 mod network; 才会把该文件编进来;文件存在 ≠ 自动成为模块。
二、可见性:默认私有
| 声明 | 谁能访问 |
|---|---|
fn item()(默认) | 仅当前模块及其后代模块 |
pub fn item() | 任何能看到该模块的地方 |
pub(crate) | 整个 crate 内可见,crate 外不可见 |
pub(super) | 仅父模块 |
pub(in path) | 指定路径内可见 |
rust
mod network {
pub fn connect() {} // 模块外可见
fn helper() {} // 私有,仅 network 内
pub(crate) fn shared() {} // 全 crate 可见,对外库隐藏
}注意「pub 字段」也要逐个标:结构体的 pub fn 能被调用,但其字段默认私有,跨模块构造必须字段也 pub 或提供构造器(对比 struct 与 impl)。
三、use 与路径
rust
use std::collections::HashMap; // 引入,直接用 HashMap
use std::io::{self, Read, Write}; // 同时引入模块自身与多项
use std::collections::HashMap as Map; // 别名
use std::collections::*; // 通配(少用)
fn f() {
let map: HashMap<String, u32> = HashMap::new();
std::mem::size_of::<u8>(); // 全路径也能直接用
}路径起点:
crate:::从当前 crate 根开始(绝对路径,推荐)。self:::当前模块;super:::父模块。- 直接
std::...:外部 crate 名(2018 edition 起无需extern crate)。
pub use 是重导出:把子模块的项提到上层,既方便调用方,也能隐藏内部目录结构(公共 API 设计常用)。
四、一个完整小例子
bash
src/
├── lib.rs
└── net/
├── mod.rs // pub mod client; pub use client::Client;
└── client.rs // pub struct Client { ... }rust
// src/net/mod.rs
pub mod client; // 声明子模块(文件被编入)
pub use client::Client; // 重导出
// src/lib.rs
mod net;
pub use net::Client; // 库使用者:use mycrate::Client;五、常见坑
- 写了文件忘了
mod xxx;:文件不会被编译,报「找不到模块」。 - 模块可见 ≠ 项可见:
pub mod里的私有函数仍不可达,要逐层pub。 - 结构体字段私有导致无法字面量构造:跨模块要么字段
pub,要么提供new()。 - 路径写错层级:模块内部用
crate::/super::,不要从文件系统位置想当然。 - 循环依赖:模块间循环
use常是边界划错,提取公共子模块或用pub use重导出解耦;crate 间循环则需拆包。
总结
Rust 以 crate 根(lib.rs/main.rs)出发的模块树组织代码,文件必须经父模块 mod xxx; 声明才会被编入,目录与文件按 cargo 约定映射;一切项默认私有,按 pub / pub(crate) / pub(super) 逐级开放且结构体字段要单独标 pub;用 use 引入路径(crate:: 绝对、self/super 相对、as 起别名),用 pub use 重导出以收窄公共 API;常见错误集中在漏声明模块、只 pub 模块没 pub 项、跨模块构造私有字段以及把循环依赖当成 use 语法问题。