当前位置: 首页 > news >正文

rust 学习(11):包、Crate、模块系统

文章目录

    • 一、回顾与导入
    • 二、核心概念
      • 什么是 Crate?
      • 什么是 Package?
    • 三、定义模块
      • 3.1 使用 `mod` 关键字
      • 3.2 模块的私有性
    • 四、路径(Path)
      • 使用 `super` 访问父模块
    • 五、use 关键字
      • 5.1 使用 `as` 重命名
      • 5.2 导入多项
      • 5.3 通配符 `*`
      • 5.4 嵌套路径
    • 六、拆分模块到多个文件
      • 6.1 传统方式(Rust 2015 风格,仍可用)
      • 6.2 现代方式(Rust 2018+,推荐)
      • 6.3 另一种现代方式(不推荐 mod.rs)
    • 七、pub use —— 重导出
    • 八、Cargo.toml 与第三方依赖
      • 8.1 添加依赖
      • 8.2 使用第三方 crate
    • 九、完整项目示例
      • 项目结构
      • Cargo.toml
      • src/lib.rs
      • src/front_of_house/mod.rs
      • src/front_of_house/hosting.rs
      • src/back_of_house.rs
      • src/main.rs
    • 十、常见陷阱与最佳实践
      • 陷阱 1:忘记添加 `pub`
      • 陷阱 2:路径混乱
      • 最佳实践总结
    • 十一、总结与速查
    • 十二、思考题
    • 参考链接

返回首页 | 上篇 | 下篇

掌握 Rust 的模块化组织 —— 包、Crate、模块、use 以及项目结构最佳实践


一、回顾与导入

前面十篇文章我们学习了 Rust 的基础语法和核心特性。随着项目规模增长,我们需要一种方式来组织代码,将功能拆分到不同的文件中,并控制哪些内容对外可见。

这就是 Rust 的模块系统的职责。

💡 Rust 的模块系统帮助你组织代码、控制私有性、管理依赖。


二、核心概念

Rust 的模块系统包含以下几个层级(从大到小):

概念说明示例
包(Package)一个或多个 Crate,有Cargo.tomlcargo new my_project
Crate一个编译单元,产生一个库或可执行文件lib.rsmain.rs
模块(Module)控制作用域和私有性的代码组织单元mod network
路径(Path)引用模块中的项crate::network::connect

什么是 Crate?

Crate 是 Rust 的编译单元。rustc每次编译,处理的都是一个 Crate。Crate 可以生成:

  • 二进制程序(有main函数)
  • 库(可被其他项目使用,没有main函数)

什么是 Package?

Package 包含:

  • 一个Cargo.toml文件
  • 至少一个 Crate(可以是库、二进制或两者都有)
典型结构: my_package/ ├── Cargo.toml ├── src/ │ ├── main.rs # 二进制 crate 根 │ └── lib.rs # 库 crate 根(可选)

三、定义模块

3.1 使用mod关键字

可以在一个文件中定义多个模块:

// src/main.rsmodfront_of_house{modhosting{fnadd_to_waitlist(){}fnseat_at_table(){}}modserving{fntake_order(){}fnserve_order(){}fntake_payment(){}}}

3.2 模块的私有性

Rust 中所有项(函数、结构体、枚举等)默认是私有的。父模块不能访问子模块的私有项,但子模块可以访问父模块的项。

modfront_of_house{pubmodhosting{// 添加 pub 让模块对外可见pubfnadd_to_waitlist(){}// 添加 pub 让函数对外可见}}fnmain(){// 需要 pub 才能访问crate::front_of_house::hosting::add_to_waitlist();}

四、路径(Path)

路径用于引用模块中的项,有两种形式:

类型语法说明
绝对路径crate::module::item从当前 crate 根开始
相对路径self::module::itemsuper::item从当前模块开始
modfront_of_house{pubmodhosting{pubfnadd_to_waitlist(){}}}fnmain(){// 绝对路径crate::front_of_house::hosting::add_to_waitlist();// 相对路径(从当前模块开始)front_of_house::hosting::add_to_waitlist();}

使用super访问父模块

fnserve_order(){}modback_of_house{fnfix_incorrect_order(){cook_order();super::serve_order();// super 指向父模块}fncook_order(){}}

五、use 关键字

use用于将路径导入作用域,简化重复引用。

modfront_of_house{pubmodhosting{pubfnadd_to_waitlist(){}}}usecrate::front_of_house::hosting;fnmain(){hosting::add_to_waitlist();// 不需要写完整路径}

5.1 使用as重命名

usestd::fmt::Result;usestd::io::ResultasIoResult;// 解决名称冲突

5.2 导入多项

usestd::collections::{HashMap,HashSet,VecDeque};// 等价于// use std::collections::HashMap;// use std::collections::HashSet;// use std::collections::VecDeque;

5.3 通配符*

usestd::collections::*;// 导入所有公共项

谨慎使用,可能造成命名冲突和可读性下降。

5.4 嵌套路径

usestd::{cmp::Ordering,collections::{HashMap,HashSet},io::{self,Write},};fnmain(){letmutmap=HashMap::new();io::stdout().write(b"hello").unwrap();}

六、拆分模块到多个文件

随着项目变大,需要将模块拆分到独立文件中。

6.1 传统方式(Rust 2015 风格,仍可用)

// src/lib.rsmodfront_of_house;// 声明模块,内容在 src/front_of_house.rspubusecrate::front_of_house::hosting;pubfneat_at_restaurant(){hosting::add_to_waitlist();}
// src/front_of_house.rspubmodhosting;// 声明子模块,内容在 src/front_of_house/hosting.rs
// src/front_of_house/hosting.rspubfnadd_to_waitlist(){}

6.2 现代方式(Rust 2018+,推荐)

使用与模块同名的目录 +mod.rs

my_crate/ ├── src/ │ ├── lib.rs │ ├── front_of_house/ │ │ ├── mod.rs # front_of_house 模块内容 │ │ └── hosting.rs # hosting 模块内容
// src/lib.rsmodfront_of_house;pubusecrate::front_of_house::hosting;pubfneat_at_restaurant(){hosting::add_to_waitlist();}
// src/front_of_house/mod.rspubmodhosting;
// src/front_of_house/hosting.rspubfnadd_to_waitlist(){println!("Added to waitlist");}

6.3 另一种现代方式(不推荐 mod.rs)

Rust 2018+ 也支持目录名对应模块,但不推荐:

my_crate/ ├── src/ │ ├── lib.rs │ ├── front_of_house.rs # 模块根 │ └── front_of_house/ # 子模块目录 │ └── hosting.rs

通常使用mod.rs方案更清晰。


七、pub use —— 重导出

pub use既可以导入项,又可以让外部访问它:

// lib.rsmodfront_of_house;pubusecrate::front_of_house::hosting;// 重导出pubfneat_at_restaurant(){hosting::add_to_waitlist();}

外部使用者:

usemy_restaurant::hosting;// 直接使用重导出的模块fnmain(){hosting::add_to_waitlist();}

八、Cargo.toml 与第三方依赖

8.1 添加依赖

[package] name = "my_project" version = "0.1.0" edition = "2021" [dependencies] rand = "0.8.5" serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.0", features = ["full"] }

8.2 使用第三方 crate

userand::Rng;useserde::{Serialize,Deserialize};fnmain(){letmutrng=rand::thread_rng();letn:u8=rng.gen();println!("随机数: {}",n);}

九、完整项目示例

让我们创建一个餐厅管理系统来演示模块系统:

项目结构

restaurant/ ├── Cargo.toml └── src/ ├── main.rs ├── lib.rs ├── front_of_house/ │ ├── mod.rs │ └── hosting.rs └── back_of_house.rs

Cargo.toml

[package] name = "restaurant" version = "0.1.0" edition = "2021"

src/lib.rs

modfront_of_house;modback_of_house;// 重导出常用项pubusecrate::front_of_house::hosting;pubusecrate::back_of_house::Breakfast;pubfneat_at_restaurant(){// 绝对路径crate::front_of_house::hosting::add_to_waitlist();// 相对路径front_of_house::hosting::seat_at_table();// 使用 Breakfastletmutmeal=Breakfast::summer("Rye");meal.toast=String::from("Wheat");println!("I'd like {} toast please",meal.toast);}

src/front_of_house/mod.rs

pubmodhosting;pubfnseat_at_table(){println!("Seating at table");}

src/front_of_house/hosting.rs

pubfnadd_to_waitlist(){println!("Added to waitlist");}fnseat_at_table(){// 私有函数println!("Seating at table (private)");}

src/back_of_house.rs

pubstructBreakfast{pubtoast:String,// 公有字段seasonal_fruit:String,// 私有字段}implBreakfast{pubfnsummer(toast:&str)->Breakfast{Breakfast{toast:String::from(toast),seasonal_fruit:String::from("peaches"),}}}pubenumAppetizer{// 枚举的变体默认都是公有的Soup,Salad,}

src/main.rs

userestaurant::{hosting,Breakfast};fnmain(){println!("=== 使用 restaurant crate ===");// 使用重导出的 hostinghosting::add_to_waitlist();// 使用 Breakfastletmutmeal=Breakfast::summer("Rye");meal.toast=String::from("Wheat");println!("Toast: {}",meal.toast);// meal.seasonal_fruit = String::from("blueberries"); // 错误:私有字段}

十、常见陷阱与最佳实践

陷阱 1:忘记添加pub

modmy_module{fnprivate_function(){}// 私有,外部无法访问}fnmain(){my_module::private_function();// ❌ 编译错误}

陷阱 2:路径混乱

// 不推荐:深层嵌套的路径usecrate::foo::bar::baz::qux::my_function;// 推荐:使用模块别名或重导出usecrate::foo::bar::baz::qux;qux::my_function();

最佳实践总结

场景推荐做法
小型项目所有代码放在main.rslib.rs
中型项目按功能拆分到同目录的多个.rs文件
大型项目使用目录 +mod.rs分层组织
暴露 API使用pub use重导出,隐藏内部结构
导入依赖Cargo.toml中声明,在代码中使用use

十一、总结与速查

概念语法说明
定义模块mod module_name { ... }内联模块
声明外部模块mod module_name;模块在其他文件
公有性pub使项对外可见
绝对路径crate::module::item从 crate 根开始
相对路径super::itemself::item从父模块或当前模块开始
导入use path::to::item简化路径
重命名use path as alias解决冲突
重导出pub use path导入并对外暴露

核心要点

  • mod定义模块,控制私有性
  • ✅ 路径可以是绝对(crate::)或相对(self::/super::
  • use将路径引入作用域
  • pub use可以重导出 API
  • ✅ 大型项目应将模块拆分到多个文件

十二、思考题

  1. 下面代码能否编译?为什么?
modouter{fnprivate(){}pubmodinner{pubfncall(){super::private();// 子模块能调用父模块的私有函数吗?}}}fnmain(){outer::inner::call();}
  1. mod声明和use导入有什么区别?

  2. 如何让外部 crate 用户只看到my_crate::something,而看不到my_crate::internal::something


参考链接

  • Rust Book - Packages and Crates
  • Rust Book - Modules
  • Rust Book - Paths
  • Rust Book - Use
  • Rust Book - Separating Files
http://www.jsqmd.com/news/1374336/

相关文章:

  • 如何快速成为Beads开源项目的核心贡献者:从零到一的完整路径
  • LineaPy 常见问题解答:新手到专家的进阶之路
  • 3步实现GPT模型零代码监控:Langfuse OpenAI集成完全指南
  • 消息队列积压问题分析与韧性架构设计
  • 高分论文的秘密|外文翻译/英文摘要这样写绝不扣分✅
  • 2026武汉电子标书制作代上传机构大盘点:怎么选?避坑攻略有哪些?靠谱服务商实力解析 - 商业大观
  • 群晖NAS终极加速方案:如何免费突破千兆网络限制
  • Gibbed.Borderlands2:终极无主之地2 modding工具包,解锁游戏自定义新可能
  • 能源行业设备缺陷上报自动化:AI Agent驱动的电力运维从“事后抢修”向“事前预测”转型全解析
  • 2026北京律所成本管控实践:用案件台账打通收案到结案全流程
  • Git与Gitee核心工作流实战:从下载、更新到上传的完整闭环
  • 深圳问鼎 工信部教考中心电池回收工程师 专业持证人才培育 - 优企甄选
  • 实战教程:用timm库快速部署inception_v3.tf_in1k模型的3种方法
  • 5分钟快速上手Xash3D:跨平台重制的Gold Source游戏引擎终极指南 [特殊字符]
  • 终极指南:5个简单步骤在PC上完美运行Switch游戏
  • 2026武汉正规标书代写公司有哪些?本地正规机构盘点、选型避坑指南及核心服务商实力深度解读 - 产业观察报
  • robot_descriptions.py:解锁190+机器人模型的终极Python工具库
  • 024、HDR sensor三种实现路径——DOL/Staggered/Split-Pixel的时序/带宽/算力代价对比与选型
  • 3分钟学会使用untrunc:快速恢复损坏MP4/MOV视频文件的终极指南
  • 读微光 035,我在「打」这个字上停了一整段
  • 8.11
  • 如何用zen-rails-base-app快速搭建Rails应用?5分钟入门指南
  • 3分钟快速解决:Windows下iPhone USB网络共享驱动终极安装指南
  • 5分钟搞定网易云音乐和QQ音乐歌词下载:163MusicLyrics工具完全指南
  • G-Helper终极指南:告别臃肿,华硕笔记本性能控制就该如此简单
  • 深度解析LCUI架构设计:C语言现代化GUI开发框架实现原理
  • 高效跨平台存档编辑:ER-Save-Editor深度实战指南
  • Hanselman.Forms主题切换功能实现:LightTheme与DarkTheme无缝切换技巧
  • 22寸行李箱选型笔记:尺寸定位、关键指标与市场样本分析
  • UFO² API文档生成:从代码注释到自动文档系统