用 rustlings 系统掌握 Rust 模块系统:pub 可见性、use 路径导入与 pub use 重导出
2026/9/5 21:17:26 网站建设 项目流程

用 rustlings 系统掌握 Rust 模块系统:pub 可见性、use 路径导入与 pub use 重导出

【免费下载链接】rustlings:crab: Small exercises to get you used to reading and writing Rust code!项目地址: https://gitcode.com/gh_mirrors/ru/rustlings

本篇围绕 rustlings 仓库中exercises/10_modules/模块章节(对应官方文档 exercises/10_modules/README.md)展开,介绍 Rust 模块系统(module system)的三个核心能力:默认私有与pub可见性控制、use/as将模块路径引入作用域并重命名、以及通过pub use向外部暴露与内部结构不同的接口。你将跟随 modules1~modules3 三道练习题的完整代码,掌握如何在真实工程中组织代码可见性与命名空间。

模块章节定位与练习构成

exercises/10_modules/README.md是 rustlings 课程中"模块"章节的导读,其核心目标是给出 Rust 模块系统的入门指引。在 rustlings 的练习体系中,该章节由三道源码文件组成,各自聚焦一个知识点:

练习文件考察重点官方提示(hint)
modules1.rsmod与可见性:模块内函数默认私有,需用pub对外暴露"Everything is private in Rust by default. But there's a keyword we can use to make something public!"(Rust 中一切默认私有,但有一个关键字可以把它变为公开)
modules2.rsuse ... as重命名 +pub use重导出提示要补齐两条use语句,并找到"两个常量都缺少的一个关键字"
modules3.rs用嵌套路径一行引入标准库模块提示UNIX_EPOCHSystemTime声明在std::time模块中,可用嵌套路径一行引入

三道练习的 hint 文本集中维护在 rustlings-macros/info.toml 的[[exercises]]配置段中,其中modules1~modules3均标记为test = false,意味着 rustlings 只要求练习编译通过modules3额外要求运行时不 panic),而不依赖单元测试断言。

modules1:模块边界与 pub 可见性

练习代码与报错

modules1.rs 构造了一个典型的"模块内部实现"场景——香肠工厂(sausage_factory模块):

// TODO: Fix the compiler error about calling a private function. mod sausage_factory { // Don't let anybody outside of this module see this! fn get_secret_recipe() -> String { String::from("Ginger") } fn make_sausage() { get_secret_recipe(); println!("sausage!"); } } fn main() { sausage_factory::make_sausage(); }

这段代码无法通过编译:main中调用sausage_factory::make_sausage()时,make_sausage没有pub修饰,属于私有项,模块外部(main所在的根作用域)不可访问。这正是 Rust 的可见性规则——一切默认私有,且可见性按模块边界逐层生效:只有当前模块及其子模块能看到当前模块中的私有项。

修复方式与官方解法

对照 solutions/10_modules/modules1.rs,官方解法只改了一处:

mod sausage_factory { fn get_secret_recipe() -> String { String::from("Ginger") } // Added `pub` before `fn` to make the function accessible outside the module. pub fn make_sausage() { get_secret_recipe(); println!("sausage!"); } } fn main() { sausage_factory::make_sausage(); }

get_secret_recipe保持私有,make_sausage加上pub。这个细节值得注意:修复的最小改动是只暴露必要的 APImake_sausage),而不必把"秘方"函数也公开。这体现了 Rust 模块设计的一个惯用做法——用模块边界封装内部实现,对外仅暴露最小公开面;调用方只能经由make_sausage间接触达get_secret_recipe

modules2:use/as 引入路径与 pub use 重导出

练习代码

modules2.rs 要求模块对外呈现一套"与内部结构不同的接口"。内部结构是两个子模块fruitsveggies,各自定义公开常量:

mod delicious_snacks { // TODO: Add the following two `use` statements after fixing them. // use self::fruits::PEAR as ???; // use self::veggies::CUCUMBER as ???; mod fruits { pub const PEAR: &str = "Pear"; pub const APPLE: &str = "Apple"; } mod veggies { pub const CUCUMBER: &str = "Cucumber"; pub const CARROT: &str = "Carrot"; } } fn main() { println!( "favorite snacks: {} and {}", delicious_snacks::fruit, delicious_snacks::veggie, ); }

注意main中期望的路径是delicious_snacks::fruitdelicious_snacks::veggie——小写、无子模块前缀,与内部fruits::PEARveggies::CUCUMBER的结构完全不同。因此需要两件事:

  1. use ... as把常量路径引入delicious_snacks作用域并重命名
  2. 让外部能沿delicious_snacks::fruit这个路径找到它们——即use本身还要公开。

修复方式:pub use 重导出

对照 solutions/10_modules/modules2.rs:

mod delicious_snacks { // Added `pub` and used the expected alias after `as`. pub use self::fruits::PEAR as fruit; pub use self::veggies::CUCUMBER as veggie; mod fruits { pub const PEAR: &str = "Pear"; pub const APPLE: &str = "Apple"; } mod veggies { pub const CUCUMBER: &str = "Cucumber"; pub const CARROT: &str = "Carrot"; } }

几个要点:

  • self::前缀:在模块内部以self指代当前模块本身,self::fruits::PEAR即"本模块下 fruits 子模块的 PEAR"。
  • as重命名use self::fruits::PEAR as fruit;创建别名fruit,使maindelicious_snacks::fruit的写法成立。
  • pub use重导出:这是官方 hint 中所说的"两个常量都缺少的一个关键字"。若只写use(不加pub),别名仅在当前模块内部可见,main依然无法访问;加上pub后,delicious_snacks模块就对外重导出了fruit/veggie两个名字,而内部真实结构(fruitsveggies子模块及常量)仍然保持私有。这正是"模块作为接口边界"的体现——外部使用者只看到delicious_snacks::fruit,看不到其内部组织。

modules3:一行引入标准库模块(嵌套路径)

modules3.rs 的场景是计算当前时间距 UNIX 纪元的秒数,代码中直接使用了SystemTimeUNIX_EPOCH,但尚未引入作用域:

// TODO: Bring `SystemTime` and `UNIX_EPOCH` from the `std::time` module into // your scope. Bonus style points if you can do it with one line! // use ???; fn main() { match SystemTime::now().duration_since(UNIX_EPOCH) { Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), Err(_) => panic!("SystemTime before UNIX EPOCH!"), } }

官方解法 solutions/10_modules/modules3.rs 用一条嵌套路径语句同时引入两个名字,拿到题目所说的"Bonus style points":

use std::time::{SystemTime, UNIX_EPOCH};

这里use的"路径"不限于自己项目的模块树,同样适用于标准库(std::time)。大括号语法use 路径::{A, B};允许在一条语句中导入同一模块下的多个项,比写两行use std::time::SystemTime; use std::time::UNIX_EPOCH;更简洁。test = false的校验方式下,该练习的通过标准是:编译通过,且运行main正常打印(若时钟早于 UNIX 纪元会触发 panic,正常系统下不会)。

rustlings 如何组织与校验这些练习

从仓库结构看,模块章节的练习文件、解法文件与校验配置是分离维护的:

  • 练习源码位于 exercises/10_modules/,配套解法位于 solutions/10_modules/,一一对应;
  • dev/Cargo.toml 将每个练习注册为 workspace 成员,并同时引入练习版与解法版两个 target,例如:
{ name = "modules1", path = "../exercises/10_modules/modules1.rs" }, { name = "modules1_sol", path = "../solutions/10_modules/modules1.rs" }, { name = "modules2", path = "../exercises/10_modules/modules2.rs" }, { name = "modules2_sol", path = "../solutions/10_modules/modules2.rs" }, { name = "modules3", path = "../exercises/10_modules/modules3.rs" }, { name = "modules3_sol", path = "../solutions/10_modules/modules3.rs" },

这说明 rustlings 的校验流程是把每个.rs练习作为独立编译单元进行编译(_sol版本则用于验证解法可编译通过);

  • 每个练习的元数据(目录、是否含测试、hint 文本)记录在 rustlings-macros/info.toml 中,模块三道题均为test = false,即纯编译校验,与 tests/test_exercises/info.toml 中带测试用例(如test_failure)的练习形成对照;
  • 练习文件顶部的// TODO:注释即为需要修改的位置,官方 hint 会给出方向而不直接给答案(如 modules1 的 hint 只提示"有一个关键字可以让项变公开")。

学习者通常通过cargo run(rustlings CLI)或cargo dev驱动开发循环来完成本章节:阅读报错 → 按 hint 方向修改 → 编译/运行通过即过关。

小结:模块三要素速查

语法作用本章节出处
mod name { ... }声明模块,划定作用域边界,内部项默认私有modules1.rs
pub使项(函数/常量/模块)对模块外部可见modules1 解法、modules2 解法
use 路径 as 别名;引入模块路径并在新作用域重命名modules2 解法
pub use ...;重导出名字,对外暴露与内部结构不同的接口modules2 解法
use a::b::{X, Y};嵌套路径,一行引入多个标准库项modules3 解法

完成本章后,建议继续回顾 Rust 官方书籍 The Book 第 7 章("Managing Growing Projects with Packages, Crates, and Modules")中"用 use 关键字把路径引入作用域"一节的pub use重导出小节,以补全本章练习涉及的完整知识背景。

【免费下载链接】rustlings:crab: Small exercises to get you used to reading and writing Rust code!项目地址: https://gitcode.com/gh_mirrors/ru/rustlings

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询