【Rust编程:从小白入坑】Rust模块系统详解
Rust模块系统总结 Rust通过模块系统(Module)组织代码,提供以下核心功能: 模块定义:使用mod关键字创建嵌套模块结构,默认私有 路径访问:支持绝对路径(crate::)和相对路径(super::) 可见性控制:pub关键字管理公开/私有访问 结构体/枚举可见性:结构体字段需单独公开,枚举变体默认公开 代码引入:use关键字简化路径,支持嵌套路径和glob运算符 模块分割:可将模块拆分
引言
随着程序规模的增长,代码组织变得越来越重要。今天我们将学习Rust的模块系统,它帮助我们组织代码、控制作用域和管理私有性。
一、模块基础
1.1 什么是模块?
模块是Rust中组织代码的方式,可以:
- 将相关的代码组织在一起
- 控制代码的可见性(公开/私有)
- 创建命名空间
1.2 定义模块
使用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() {}
}
}
fn main() {
// 模块内的函数默认是私有的
}
1.3 模块树
crate
└── front_of_house
├── hosting
│ ├── add_to_waitlist
│ └── seat_at_table
└── serving
├── take_order
├── serve_order
└── take_payment
二、路径
2.1 绝对路径和相对路径
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {
println!("添加到等待列表");
}
}
}
pub fn eat_at_restaurant() {
// 绝对路径
crate::front_of_house::hosting::add_to_waitlist();
// 相对路径
front_of_house::hosting::add_to_waitlist();
}
fn main() {
eat_at_restaurant();
}
路径规则:
- 绝对路径:从crate根开始,使用
crate - 相对路径:从当前模块开始
2.2 pub关键字
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
fn seat_at_table() {} // 私有函数
}
}
pub fn eat_at_restaurant() {
front_of_house::hosting::add_to_waitlist(); // ✅ 可以
// front_of_house::hosting::seat_at_table(); // ❌ 私有
}
fn main() {
eat_at_restaurant();
}
2.3 super关键字
使用super访问父模块:
fn serve_order() {
println!("上菜");
}
mod back_of_house {
fn fix_incorrect_order() {
cook_order();
super::serve_order(); // 调用父模块的函数
}
fn cook_order() {
println!("烹饪");
}
}
fn main() {}
三、结构体和枚举的可见性
3.1 公开结构体
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("桃子"),
}
}
}
}
fn main() {
let mut meal = back_of_house::Breakfast::summer("黑麦");
meal.toast = String::from("小麦"); // ✅ 可以修改公开字段
println!("我想要{}面包", meal.toast);
// meal.seasonal_fruit = String::from("蓝莓"); // ❌ 私有字段
}
3.2 公开枚举
mod back_of_house {
pub enum Appetizer {
Soup,
Salad,
}
}
fn main() {
// 枚举的所有变体都是公开的
let order1 = back_of_house::Appetizer::Soup;
let order2 = back_of_house::Appetizer::Salad;
}
四、use关键字
4.1 基本使用
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {
println!("添加到等待列表");
}
}
}
use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist(); // 简化调用
}
fn main() {
eat_at_restaurant();
}
4.2 use的惯用方式
use std::collections::HashMap; // ✅ 对于类型
use std::fmt::Result;
use std::io::Result as IoResult; // 重命名避免冲突
fn main() {
let mut map = HashMap::new();
map.insert(1, 2);
}
4.3 嵌套路径
// ❌ 繁琐的方式
// use std::io;
// use std::io::Write;
// use std::cmp::Ordering;
// ✅ 使用嵌套路径
use std::{cmp::Ordering, io::{self, Write}};
fn main() {
println!("使用嵌套路径简化导入");
}
4.4 glob运算符
use std::collections::*; // 导入所有公开项
fn main() {
let mut map = HashMap::new();
let mut set = HashSet::new();
}
注意:glob运算符会使代码难以理解,一般只在测试模块中使用。
五、将模块分割到不同文件
5.1 项目结构
restaurant/
├── Cargo.toml
└── src/
├── main.rs
├── front_of_house.rs
└── front_of_house/
├── hosting.rs
└── serving.rs
5.2 main.rs
mod front_of_house;
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
fn main() {
eat_at_restaurant();
}
5.3 front_of_house.rs
pub mod hosting;
pub mod serving;
5.4 front_of_house/hosting.rs
pub fn add_to_waitlist() {
println!("添加到等待列表");
}
pub fn seat_at_table() {
println!("安排座位");
}
5.5 front_of_house/serving.rs
pub fn take_order() {
println!("点餐");
}
pub fn serve_order() {
println!("上菜");
}
pub fn take_payment() {
println!("结账");
}
六、实战示例
示例1:数学库
项目结构:
math_lib/
├── Cargo.toml
└── src/
├── lib.rs
├── geometry.rs
├── geometry/
│ ├── circle.rs
│ └── rectangle.rs
└── statistics.rs
src/lib.rs:
pub mod geometry;
pub mod statistics;
pub fn version() -> &'static str {
"1.0.0"
}
src/geometry.rs:
pub mod circle;
pub mod rectangle;
pub trait Shape {
fn area(&self) -> f64;
fn perimeter(&self) -> f64;
}
src/geometry/circle.rs:
use std::f64::consts::PI;
use super::Shape;
pub struct Circle {
radius: f64,
}
impl Circle {
pub fn new(radius: f64) -> Circle {
Circle { radius }
}
}
impl Shape for Circle {
fn area(&self) -> f64 {
PI * self.radius * self.radius
}
fn perimeter(&self) -> f64 {
2.0 * PI * self.radius
}
}
src/geometry/rectangle.rs:
use super::Shape;
pub struct Rectangle {
width: f64,
height: f64,
}
impl Rectangle {
pub fn new(width: f64, height: f64) -> Rectangle {
Rectangle { width, height }
}
pub fn is_square(&self) -> bool {
self.width == self.height
}
}
impl Shape for Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
fn perimeter(&self) -> f64 {
2.0 * (self.width + self.height)
}
}
src/statistics.rs:
pub fn mean(numbers: &[f64]) -> f64 {
if numbers.is_empty() {
return 0.0;
}
let sum: f64 = numbers.iter().sum();
sum / numbers.len() as f64
}
pub fn median(numbers: &mut [f64]) -> f64 {
if numbers.is_empty() {
return 0.0;
}
numbers.sort_by(|a, b| a.partial_cmp(b).unwrap());
let mid = numbers.len() / 2;
if numbers.len() % 2 == 0 {
(numbers[mid - 1] + numbers[mid]) / 2.0
} else {
numbers[mid]
}
}
pub fn mode(numbers: &[i32]) -> Option<i32> {
use std::collections::HashMap;
let mut counts = HashMap::new();
for &num in numbers {
*counts.entry(num).or_insert(0) += 1;
}
counts
.into_iter()
.max_by_key(|&(_, count)| count)
.map(|(num, _)| num)
}
使用库:
use math_lib::geometry::{Shape, circle::Circle, rectangle::Rectangle};
use math_lib::statistics;
fn main() {
let circle = Circle::new(5.0);
println!("圆的面积: {:.2}", circle.area());
let rect = Rectangle::new(10.0, 5.0);
println!("矩形的面积: {:.2}", rect.area());
println!("是正方形: {}", rect.is_square());
let numbers = vec![1.0, 2.0, 3.0, 4.0, 5.0];
println!("平均值: {:.2}", statistics::mean(&numbers));
let mut numbers2 = vec![5.0, 2.0, 8.0, 1.0, 9.0];
println!("中位数: {:.2}", statistics::median(&mut numbers2));
}
示例2:Web服务器模块
项目结构:
web_server/
├── Cargo.toml
└── src/
├── main.rs
├── server.rs
├── router.rs
├── handlers/
│ ├── mod.rs
│ ├── api.rs
│ └── static_files.rs
└── middleware/
├── mod.rs
├── logger.rs
└── auth.rs
src/server.rs:
use std::net::TcpListener;
pub struct Server {
address: String,
}
impl Server {
pub fn new(address: &str) -> Server {
Server {
address: address.to_string(),
}
}
pub fn run(&self) {
println!("服务器运行在 {}", self.address);
let listener = TcpListener::bind(&self.address)
.expect("无法绑定地址");
for stream in listener.incoming() {
match stream {
Ok(_stream) => {
println!("新连接");
}
Err(e) => {
eprintln!("连接错误: {}", e);
}
}
}
}
}
src/router.rs:
use std::collections::HashMap;
pub type Handler = fn(&str) -> String;
pub struct Router {
routes: HashMap<String, Handler>,
}
impl Router {
pub fn new() -> Router {
Router {
routes: HashMap::new(),
}
}
pub fn add_route(&mut self, path: &str, handler: Handler) {
self.routes.insert(path.to_string(), handler);
}
pub fn route(&self, path: &str) -> Option<&Handler> {
self.routes.get(path)
}
}
src/handlers/mod.rs:
pub mod api;
pub mod static_files;
pub fn not_found() -> String {
String::from("404 Not Found")
}
src/handlers/api.rs:
pub fn health_check(_req: &str) -> String {
String::from(r#"{"status": "ok"}"#)
}
pub fn get_users(_req: &str) -> String {
String::from(r#"{"users": []}"#)
}
src/middleware/mod.rs:
pub mod logger;
pub mod auth;
pub trait Middleware {
fn process(&self, request: &str) -> String;
}
src/middleware/logger.rs:
use super::Middleware;
pub struct Logger;
impl Logger {
pub fn new() -> Logger {
Logger
}
}
impl Middleware for Logger {
fn process(&self, request: &str) -> String {
println!("[LOG] 请求: {}", request);
request.to_string()
}
}
src/main.rs:
mod server;
mod router;
mod handlers;
mod middleware;
use server::Server;
use router::Router;
use handlers::api;
use middleware::logger::Logger;
fn main() {
let mut router = Router::new();
router.add_route("/health", api::health_check);
router.add_route("/users", api::get_users);
let logger = Logger::new();
println!("Web服务器启动");
// let server = Server::new("127.0.0.1:8080");
// server.run();
}
示例3:配置管理系统
src/config/mod.rs:
pub mod database;
pub mod server;
pub mod logging;
use std::fs;
use std::error::Error;
pub struct Config {
pub database: database::DatabaseConfig,
pub server: server::ServerConfig,
pub logging: logging::LogConfig,
}
impl Config {
pub fn from_file(path: &str) -> Result<Config, Box<dyn Error>> {
let content = fs::read_to_string(path)?;
// 这里应该解析配置文件
Ok(Config {
database: database::DatabaseConfig::default(),
server: server::ServerConfig::default(),
logging: logging::LogConfig::default(),
})
}
pub fn default() -> Config {
Config {
database: database::DatabaseConfig::default(),
server: server::ServerConfig::default(),
logging: logging::LogConfig::default(),
}
}
}
src/config/database.rs:
#[derive(Debug)]
pub struct DatabaseConfig {
pub host: String,
pub port: u16,
pub username: String,
pub password: String,
pub database: String,
pub max_connections: u32,
}
impl DatabaseConfig {
pub fn default() -> DatabaseConfig {
DatabaseConfig {
host: String::from("localhost"),
port: 5432,
username: String::from("postgres"),
password: String::from(""),
database: String::from("myapp"),
max_connections: 10,
}
}
pub fn connection_string(&self) -> String {
format!(
"postgresql://{}:{}@{}:{}/{}",
self.username,
self.password,
self.host,
self.port,
self.database
)
}
}
src/config/server.rs:
#[derive(Debug)]
pub struct ServerConfig {
pub host: String,
pub port: u16,
pub workers: usize,
pub timeout: u64,
}
impl ServerConfig {
pub fn default() -> ServerConfig {
ServerConfig {
host: String::from("0.0.0.0"),
port: 8080,
workers: 4,
timeout: 30,
}
}
pub fn address(&self) -> String {
format!("{}:{}", self.host, self.port)
}
}
src/config/logging.rs:
#[derive(Debug)]
pub enum LogLevel {
Debug,
Info,
Warning,
Error,
}
#[derive(Debug)]
pub struct LogConfig {
pub level: LogLevel,
pub file: Option<String>,
pub console: bool,
}
impl LogConfig {
pub fn default() -> LogConfig {
LogConfig {
level: LogLevel::Info,
file: None,
console: true,
}
}
}
七、re-exporting
7.1 使用pub use重导出
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();
}
fn main() {
// 外部代码可以这样使用:
// use restaurant::hosting;
// hosting::add_to_waitlist();
}
7.2 创建方便的API
// 内部结构
mod shapes {
pub mod circle {
pub struct Circle {
pub radius: f64,
}
}
pub mod rectangle {
pub struct Rectangle {
pub width: f64,
pub height: f64,
}
}
}
// 重导出,简化外部使用
pub use shapes::circle::Circle;
pub use shapes::rectangle::Rectangle;
fn main() {
// 用户可以直接使用
let c = Circle { radius: 5.0 };
let r = Rectangle { width: 10.0, height: 5.0 };
}
八、包和Crate
8.1 包的结构
my_project/
├── Cargo.toml
├── Cargo.lock
├── src/
│ ├── main.rs # 二进制crate根
│ ├── lib.rs # 库crate根
│ └── bin/
│ ├── tool1.rs # 额外的二进制crate
│ └── tool2.rs
├── tests/ # 集成测试
├── benches/ # 基准测试
└── examples/ # 示例
8.2 Cargo.toml配置
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = "1.0"
[dev-dependencies]
criterion = "0.5"
[[bin]]
name = "tool1"
path = "src/bin/tool1.rs"
[[bin]]
name = "tool2"
path = "src/bin/tool2.rs"
九、最佳实践
9.1 模块组织原则
- 按功能分组:相关的代码放在同一模块
- 保持浅层次:避免过深的模块嵌套
- 清晰的命名:模块名应该描述其内容
- 最小化公开接口:只公开必要的部分
9.2 示例:良好的模块结构
// ✅ 好的结构
mod user {
pub struct User {
id: u32,
name: String,
}
impl User {
pub fn new(id: u32, name: String) -> User {
User { id, name }
}
pub fn id(&self) -> u32 {
self.id
}
// 私有辅助函数
fn validate_name(name: &str) -> bool {
!name.is_empty()
}
}
}
9.3 避免循环依赖
// ❌ 不好:循环依赖
// mod a {
// use super::b::B;
// }
// mod b {
// use super::a::A;
// }
// ✅ 好:提取共享接口
mod common {
pub trait Processor {}
}
mod a {
use super::common::Processor;
}
mod b {
use super::common::Processor;
}
十、练习题
练习1:图书馆系统
创建一个模块化的图书馆管理系统:
// src/lib.rs
pub mod book;
pub mod member;
pub mod library;
// src/book.rs
#[derive(Debug, Clone)]
pub struct Book {
pub isbn: String,
pub title: String,
pub author: String,
pub available: bool,
}
impl Book {
pub fn new(isbn: String, title: String, author: String) -> Book {
Book {
isbn,
title,
author,
available: true,
}
}
}
// src/member.rs
#[derive(Debug)]
pub struct Member {
pub id: u32,
pub name: String,
pub borrowed_books: Vec<String>,
}
impl Member {
pub fn new(id: u32, name: String) -> Member {
Member {
id,
name,
borrowed_books: Vec::new(),
}
}
}
// src/library.rs
use crate::book::Book;
use crate::member::Member;
pub struct Library {
books: Vec<Book>,
members: Vec<Member>,
}
impl Library {
pub fn new() -> Library {
Library {
books: Vec::new(),
members: Vec::new(),
}
}
pub fn add_book(&mut self, book: Book) {
self.books.push(book);
}
pub fn add_member(&mut self, member: Member) {
self.members.push(member);
}
}
练习2:工具函数库
创建一个包含多个工具模块的库:
// src/lib.rs
pub mod string_utils;
pub mod math_utils;
pub mod file_utils;
// 重导出常用函数
pub use string_utils::capitalize;
pub use math_utils::fibonacci;
总结
本文学习了:
✅ 模块的定义和使用
✅ 路径和可见性控制
✅ use关键字简化路径
✅ 将模块分割到文件
✅ 包和crate的组织
✅ 最佳实践
核心要点:
- 使用mod定义模块
- pub控制可见性
- use简化路径
- 模块可以分割到多个文件
- 合理组织代码结构
开放原子旋武开源社区(简称“旋武社区”)是由开放原子开源基金会孵化及运营的技术社区,致力于在中国推广和发展Rust编程语言生态,推动Rust在操作系统、终端设备、安全技术、基础软件等关键领域的产业落地,构建安全、可靠、高效的软件基础设施。
更多推荐


所有评论(0)