# Rust Package、Crate、Module 练习题 > 建议先手动写出每道题的答案,再运行代码验证。部分题目涉及多文件组织,请实际创建对应目录和文件来练习。 ## 目录 - [一、概念辨析题](#一概念辨析题) - [二、填空题:补充代码](#二填空题补充代码) - [三、找出并修复错误](#三找出并修复错误) - [四、实战题:组织代码](#四实战题组织代码) - [五、综合思考题](#五综合思考题) - [参考答案](#参考答案) --- ## 一、概念辨析题 判断以下说法是否正确,并简要说明原因。 ### 题目 1-1 > 一个 Package 只能包含一个 Crate。 ### 题目 1-2 > `main.rs` 和 `lib.rs` 分别对应二进制 Crate 和库 Crate 的根文件。 ### 题目 1-3 > 在模块树中,父模块默认可以访问子模块中的私有项。 ### 题目 1-4 > 使用 `use` 关键字将模块或项引入作用域后,其子模块也会自动被引入。 ### 题目 1-5 > `cargo new my_project` 默认会创建一个二进制 Crate。 ### 题目 1-6 > 同一个文件中可以定义多个 `mod` 模块。 ### 题目 1-7 > `pub use` 的作用完全等同于 `use`,只是书写风格不同。 ### 题目 1-8 > 在一个 Package 中,`src/bin/` 目录下的每个 `.rs` 文件都会被编译为一个独立的二进制 Crate。 --- ## 二、填空题:补充代码 补全下列代码使其能通过编译并达到期望输出。 ### 题目 2-1:定义模块 ```rust // 填空:定义一个名为 network 的模块,内部包含一个名为 connect 的函数 ________ network { fn connect() { println!("已连接"); } } fn main() { // 填空:调用 network 模块中的 connect 函数 network::________(); } // 期望输出:已连接 ``` ### 题目 2-2:pub 可见性 ```rust mod garden { // 填空:使 plant 函数能够被模块外部访问 ________ fn plant() -> &'static str { "玫瑰花" } fn water() { println!("浇水..."); } } fn main() { let flower = garden::plant(); println!("种了{}", flower); // 下面这行取消注释会怎样? // garden::water(); } // 期望输出:种了玫瑰花 ``` ### 题目 2-3:use 关键字 ```rust mod front_of_house { pub mod hosting { pub fn add_to_waitlist() { println!("已加入等候列表"); } pub fn seat_at_table() { println!("已入座"); } } } fn main() { // 填空:使用 use 将 hosting 模块引入当前作用域 ________ front_of_house::hosting; hosting::add_to_waitlist(); hosting::seat_at_table(); } // 期望输出: // 已加入等候列表 // 已入座 ``` ### 题目 2-4:super 关键字 ```rust fn serve_order() { println!("上菜!"); } mod back_of_house { fn cook() { println!("烹饪中..."); } // 填空:使用 super 调用父模块中的 serve_order 函数 pub fn deliver() { cook(); ________::serve_order(); } } fn main() { // 填空:正确调用 deliver 函数 ________(); } // 期望输出: // 烹饪中... // 上菜! ``` ### 题目 2-5:as 别名 ```rust use std::fmt::Result as FmtResult; // 填空:将 std::io::Result 以别名 IoResult 引入 use std::io::Result ________ ________; fn main() { // 直接使用别名调用 Ok 构造函数 let _r1: FmtResult = Ok(()); let _r2: IoResult<()> = Ok(()); println!("两种 Result 都能正常使用!"); } ``` ### 题目 2-6:嵌套路径导入 ```rust // 下面的导入使用了 3 行 use 语句 // use std::cmp::Ordering; // use std::io; // use std::io::Write; // 填空:替换为一行嵌套路径的 use 语句 use std::________; use std::________::{self, Write}; fn main() { println!("模块导入成功!"); } ``` ### 题目 2-7:pub use 重导出 ```rust mod inner { pub fn secret() -> &'static str { "内部机密数据" } } // 填空:将 inner::secret 重导出为公开接口,使外部可以通过 crate::config 访问 ________ inner::secret as config; fn main() { // 填空:通过新的路径名调用 println!("{}", ________()); } // 期望输出:内部机密数据 ``` ### 题目 2-8:模块拆分到文件 假设 `src/main.rs` 中有以下代码,需要将 `garden` 模块拆分到单独的文件中。 ```rust // ===== src/main.rs ===== mod garden; fn main() { garden::grow(); } // 期望输出:植物正在生长... // ===== 填空:写出 src/garden.rs 的内容 ===== ________ fn grow() { println!("植物正在生长..."); } ``` ### 题目 2-9:模块拆分到目录 假设有以下模块结构,需要将 `restaurant` 模块拆分到 `src/restaurant/` 目录中。 ```rust // ===== src/main.rs ===== mod restaurant; fn main() { restaurant::front::serve(); } // 期望输出:上菜中... // ===== 填空:写出需要的文件及其内容 ===== // 文件 1: src/restaurant/________ // 文件 2: src/restaurant/________ // restaurant/________ 内容: pub mod front; // restaurant/________ 内容: pub fn serve() { println!("上菜中..."); } ``` --- ## 三、找出并修复错误 以下每段代码都有编译错误,请指出错误并写出修正后的代码。 ### 题目 3-1 ```rust mod house { fn open_door() { println!("门开了"); } } fn main() { house::open_door(); } ``` ### 题目 3-2 ```rust mod front { pub fn greet() { println!("欢迎光临!"); } } fn main() { use front; greet(); } ``` ### 题目 3-3 ```rust mod math { pub mod operations { pub fn add(a: i32, b: i32) -> i32 { a + b } } } fn main() { use math::operations; println!("{}", add(3, 5)); } ``` ### 题目 3-4 ```rust mod a { pub mod b { pub fn hello() { println!("hello from b"); } } } fn main() { use a::b; // 想要同时使用模块 b 和 c(c 不存在) use a::c; b::hello(); } ``` ### 题目 3-5 ```rust mod outer { mod inner { pub fn secret_data() -> &'static str { "机密" } } pub fn reveal() { inner::secret_data(); } } fn main() { outer::reveal(); // 下面这行是否可以? // outer::inner::secret_data(); } ``` ### 题目 3-6 ```rust mod food { 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 = food::Breakfast::summer("黑麦面包"); meal.toast = String::from("全麦面包"); println!("我要{}吐司", meal.toast); // 下面这行取消注释会怎样? // meal.seasonal_fruit = String::from("蓝莓"); } ``` ### 题目 3-7 ```rust // ===== Cargo.toml ===== // [package] // name = "my_project" // version = "0.1.0" // edition = "2021" // ===== src/main.rs ===== use rand::Rng; fn main() { let mut rng = rand::thread_rng(); let n: i32 = rng.gen_range(1..100); println!("随机数: {}", n); } // 运行 cargo build 时报错:can't find crate for `rand` ``` ### 题目 3-8 ```rust use std::collections::HashMap; use std::collections::HashSet; fn main() { let mut map: HashMap<&str, i32> = HashMap::new(); map.insert("one", 1); let mut set: HashSet = HashSet::new(); set.insert(1); println!("HashMap: {:?}", map); println!("HashSet: {:?}", set); } // 虽然编译通过,但如何将两个 use 语句合并为一行? ``` --- ## 四、实战题:组织代码 ### 题目 4-1:餐厅管理系统 请按以下要求组织一个餐厅管理系统的模块结构,并实现全部代码。 **模块结构要求:** ``` restaurant (库 Crate) ├── front_of_house/ │ ├── mod.rs → pub mod hosting; pub mod serving; │ ├── hosting.rs → pub fn add_to_waitlist() { ... } │ │ pub fn seat_at_table() { ... } │ └── serving.rs → pub fn take_order() { ... } │ pub fn serve_order() { ... } │ pub fn take_payment() { ... } ├── back_of_house.rs → pub fn cook() { ... } │ fn wash_dishes() { ... } ← 私有函数 │ pub fn clean_up() { ... } 调用 wash_dishes() ├── menu.rs → pub enum Dish { ... } │ impl Dish { fn price(&self) -> f64 } └── lib.rs → pub mod front_of_house; pub mod back_of_house; pub mod menu; pub fn eat_at_restaurant() { 演示调用各模块 } ``` **要求:** 1. 在 `menu.rs` 中定义 `Dish` 枚举,包含以下变体和价格: - `Steak` → 168.0 - `Salad` → 38.0 - `Pasta` → 58.0 - `Water` → 0.0(免费) 2. 为 `Dish` 实现 `price(&self) -> f64` 方法 3. 实现 `eat_at_restaurant()` 函数,演示完整的用餐流程: - 加入等候列表 - 入座 - 点菜(点一个牛排和一份沙拉) - 上菜 - 结账(打印总价) - 清理 4. 创建对应的目录结构,写出所有文件的完整代码 ### 题目 4-2:数学工具库 创建一个名为 `math_tools` 的库 Crate,按以下层级组织代码。 **模块结构:** ``` math_tools (库 Crate) ├── lib.rs ├── basic/ │ ├── mod.rs → pub mod arithmetic; pub mod compare; │ ├── arithmetic.rs → pub fn add, sub, mul, div │ └── compare.rs → pub fn min, max, is_even ├── advanced/ │ ├── mod.rs → pub mod stats; pub mod geometry; │ ├── stats.rs → pub fn mean, median, variance │ └── geometry.rs → pub fn circle_area, rect_area, triangle_area └── utils.rs → pub fn is_prime(n: u32) -> bool pub fn factorial(n: u32) -> u64 ``` **要求:** 1. 实现全部函数 2. `lib.rs` 中使用 `pub use` 将以下函数重导出为库的顶层接口: - `add`、`mean`、`is_prime`、`circle_area` 3. 在 `lib.rs` 中写测试(`#[cfg(test)] mod tests`)验证以下场景: - `add(2, 3) == 5` - `mean(&[1.0, 2.0, 3.0, 4.0, 5.0]) == 3.0` - `is_prime(17)` 和 `is_prime(18)` - `circle_area(1.0)` 约等于 π ### 题目 4-3:多二进制 Crate 的 Package 创建一个 Package,包含一个库 Crate 和两个二进制 Crate。 **结构:** ``` my_app/ ├── Cargo.toml → package name = "my_app" ├── src/ │ ├── lib.rs → 库 Crate:定义 Config 结构体,包含 host, port, debug 字段 │ │ 和 parse_args 函数,解析命令行参数 │ └── bin/ │ ├── server.rs → 二进制 Crate:启动一个模拟服务器,打印配置信息 │ └── client.rs → 二进制 Crate:模拟连接到服务器,打印连接信息 ``` **要求:** 1. 库中定义 `Config` 结构体: ```rust pub struct Config { pub host: String, pub port: u16, pub debug: bool, } ``` 2. 库中实现 `Config` 的 `new` 关联函数(使用默认值) 3. `server.rs` 调用库的 `Config::new()`,打印 `"服务器启动于 {host}:{port}"`,如果 debug 为 true 再打印调试信息 4. `client.rs` 调用库的 `Config::new()`,打印 `"客户端连接到 {host}:{port}"` 5. 创建完整的目录结构,写出所有文件内容 --- ## 五、综合思考题 ### 题目 5-1 分析以下模块结构。假设当前在 `crate::outer::middle::inner` 模块中,有哪些方式可以访问 `crate::outer::top_level` 中的 `value` 函数?请写出至少三种不同的路径写法。 ```rust // lib.rs pub mod outer { pub fn top_level() {} pub mod middle { pub mod inner { pub fn deep() { // 在此处调用 outer::top_level() } } } } pub mod another { pub fn value() { println!("another value"); } } ``` ### 题目 5-2 对比以下三种 `use` 导入方式的优缺点和使用场景: ```rust // 方式 A:导入模块本身 use std::collections; // 使用: collections::HashMap::new() // 方式 B:导入具体类型 use std::collections::HashMap; // 使用: HashMap::new() // 方式 C:通配符导入 use std::collections::*; // 使用: HashMap::new(), HashSet::new(), BTreeMap::new() ``` ### 题目 5-3 Rust 的可见性规则中,`pub` 的"公开"是相对于**模块路径**而言的,而不是公开给所有人。请解释以下代码中为什么 `outer::inner::secret` 虽然标记为 `pub`,但在 `main` 中仍然无法直接访问。 ```rust mod outer { mod inner { // inner 模块本身是私有的 pub fn secret() { println!("秘密"); } } pub fn reveal() { inner::secret(); // 可以,因为 outer 是 inner 的父模块 } } fn main() { outer::reveal(); // 可以 // outer::inner::secret(); // 取消注释会怎样? } ``` ### 题目 5-4 阅读以下代码,回答: ```rust mod parent { pub fn parent_func() { println!("父函数"); } pub mod child { pub fn child_func() { // 如何在 child 模块中调用 parent_func()? } } } mod sibling { pub fn sibling_func() { // 如何在此处调用 parent::parent_func()? } } ``` 1. 在 `child` 模块中调用 `parent_func()` 应该使用什么路径?(写出具体写法) 2. 在 `sibling` 模块中调用 `parent_func()` 应该使用什么路径? 3. `super` 和 `crate` 分别指代什么?各自适用于什么场景? ### 题目 5-5 `pub mod` 和 `pub use` 有什么区别?以下两种写法分别适用于什么场景? ```rust // 写法 A:嵌套模块 + 重导出 mod internal { pub fn helper() {} } pub use internal::helper; // 写法 B:先定义公开模块,再导入使用 pub mod api { pub fn helper() {} } ``` --- ## 参考答案 > 请独立完成再查看答案。
点击展开答案 ### 一、概念辨析题 **1-1**:❌ 错误。一个 Package 最多包含一个库 Crate,但可以包含任意多个二进制 Crate。例如 `src/main.rs` 是一个二进制 Crate,`src/bin/` 下的每个文件也是独立的二进制 Crate,同时还可以有一个 `src/lib.rs` 作为库 Crate。 **1-2**:✅ 正确。`src/main.rs` 是二进制 Crate 的根文件(crate root),`src/lib.rs` 是库 Crate 的根文件。Cargo 会将根文件传递给 `rustc` 来构建 crate。 **1-3**:❌ 错误。在模块树中,**子模块可以访问父模块中的所有项(包括私有项)**,但反过来不成立——父模块不能访问子模块中的私有项。要将子模块的项暴露给外部,必须用 `pub` 标记。 **1-4**:❌ 错误。`use` 只引入指定的路径,不会自动引入子模块。例如 `use std::collections;` 只引入 `collections` 模块本身,`collections` 下的 `HashMap` 等仍需要通过 `collections::HashMap` 访问。 **1-5**:✅ 正确。`cargo new my_project` 创建的模板包含 `src/main.rs`,是一个二进制 Crate。`cargo new my_lib --lib` 创建的是库 Crate(`src/lib.rs`)。 **1-6**:✅ 正确。同一个文件中可以定义任意多个 `mod` 块,每个块成为一个独立的模块。 **1-7**:❌ 错误。`use` 将路径引入当前作用域供自己使用,外部代码无法感知。`pub use` 是**重导出(re-exporting)**,不仅引入当前作用域,还将其作为当前模块的公开 API 暴露给外部使用者。 **1-8**:✅ 正确。`src/bin/` 目录下的每个 `.rs` 文件会被 Cargo 自动编译为独立的二进制 Crate,名称等于文件名(不含扩展名)。 ### 二、填空题 **2-1**: ```rust mod network { fn connect() { println!("已连接"); } } fn main() { network::connect(); } ``` **2-2**: ```rust mod garden { pub fn plant() -> &'static str { "玫瑰花" } fn water() { println!("浇水..."); } } fn main() { let flower = garden::plant(); println!("种了{}", flower); // garden::water(); 取消注释会报错:water 是私有函数 } ``` **2-3**: ```rust use front_of_house::hosting; ``` **2-4**: ```rust pub fn deliver() { cook(); super::serve_order(); } fn main() { back_of_house::deliver(); } ``` **2-5**: ```rust use std::io::Result as IoResult; ``` **2-6**: ```rust use std::{cmp::Ordering, io::{self, Write}}; ``` **2-7**: ```rust pub use inner::secret as config; fn main() { println!("{}", config()); } ``` **2-8**: ``` 文件: src/garden.rs ``` ```rust pub fn grow() { println!("植物正在生长..."); } ``` **2-9**: ``` 文件 1: src/restaurant/mod.rs 内容: pub mod front; 文件 2: src/restaurant/front.rs 内容: pub fn serve() { println!("上菜中..."); } ``` ### 三、修复错误 **3-1**:`open_door` 是私有函数,模块外部无法访问。修复:加 `pub`。 ```rust mod house { pub fn open_door() { println!("门开了"); } } ``` **3-2**:`use front;` 只引入了模块,没有引入函数。函数名本身不在作用域中。修复: ```rust use front::greet; // 或 use front; 后调用 front::greet(); ``` **3-3**:`use math::operations;` 引入的是模块,`add` 需要通过 `operations::add()` 调用。修复: ```rust use math::operations::add; println!("{}", add(3, 5)); ``` **3-4**:模块 `a::c` 不存在。如果 `c` 不需要,直接删除该行。如果想引入两个模块,应等模块存在。此题故意制造了一个引入不存在的模块的错误。 **3-5**:主函数中 `outer::inner::secret_data()` **不能**使用。虽然 `secret_data` 标记了 `pub`,但 `inner` 模块本身是私有的(没有 `pub mod`),外部无法通过私有模块访问其内部的任何项。修复:将 `mod inner` 改为 `pub mod inner`。 **3-6**:取消注释会报错,因为 `seasonal_fruit` 字段是私有的,即便结构体实例是 `mut`,也不能修改私有字段。只有直接拥有该结构体的模块才能访问私有字段。但如果改为: ```rust meal.seasonal_fruit = String::from("蓝莓"); ``` 编译错误:`seasonal_fruit` is private。外模块只能修改 `pub` 字段。 **3-7**:`Cargo.toml` 中未添加 `rand` 依赖。修复:在 `[dependencies]` 下添加: ```toml [dependencies] rand = "0.8" ``` 然后运行 `cargo build`,Cargo 会自动下载并编译 `rand`。 **3-8**:合并为: ```rust use std::collections::{HashMap, HashSet}; ``` ### 四、实战题 **4-1 餐厅管理系统:** 文件结构: ``` src/ ├── lib.rs ├── front_of_house/ │ ├── mod.rs │ ├── hosting.rs │ └── serving.rs ├── back_of_house.rs └── menu.rs ``` ```rust // src/lib.rs pub mod front_of_house; pub mod back_of_house; pub mod menu; use menu::Dish; pub fn eat_at_restaurant() { front_of_house::hosting::add_to_waitlist(); front_of_house::hosting::seat_at_table(); let order = vec![Dish::Steak, Dish::Salad]; front_of_house::serving::take_order(order.clone()); front_of_house::serving::serve_order(); let total: f64 = order.iter().map(|d| d.price()).sum(); println!("总消费: {:.2} 元", total); front_of_house::serving::take_payment(); back_of_house::clean_up(); } ``` ```rust // src/front_of_house/mod.rs pub mod hosting; pub mod serving; ``` ```rust // src/front_of_house/hosting.rs pub fn add_to_waitlist() { println!("已加入等候列表"); } pub fn seat_at_table() { println!("已入座"); } ``` ```rust // src/front_of_house/serving.rs use crate::menu::Dish; pub fn take_order(dishes: Vec) { print!("点菜: "); for (i, dish) in dishes.iter().enumerate() { if i > 0 { print!(", "); } print!("{:?}", dish); } println!(); } pub fn serve_order() { println!("上菜完成!"); } pub fn take_payment() { println!("结账完成!"); } ``` ```rust // src/back_of_house.rs pub fn cook() { println!("烹饪中..."); } fn wash_dishes() { println!("洗碗中..."); } pub fn clean_up() { cook(); println!("厨房已清理"); wash_dishes(); } ``` ```rust // src/menu.rs #[derive(Debug, Clone)] pub enum Dish { Steak, Salad, Pasta, Water, } impl Dish { pub fn price(&self) -> f64 { match self { Dish::Steak => 168.0, Dish::Salad => 38.0, Dish::Pasta => 58.0, Dish::Water => 0.0, } } } ``` **4-2 数学工具库:** 文件结构: ``` src/ ├── lib.rs ├── basic/ │ ├── mod.rs │ ├── arithmetic.rs │ └── compare.rs ├── advanced/ │ ├── mod.rs │ ├── stats.rs │ └── geometry.rs └── utils.rs ``` ```rust // src/lib.rs pub mod basic; pub mod advanced; pub mod utils; pub use basic::arithmetic::add; pub use advanced::stats::mean; pub use advanced::geometry::circle_area; pub use utils::is_prime; #[cfg(test)] mod tests { use super::*; #[test] fn test_add() { assert_eq!(add(2, 3), 5); } #[test] fn test_mean() { assert_eq!(mean(&[1.0, 2.0, 3.0, 4.0, 5.0]), 3.0); } #[test] fn test_is_prime() { assert!(is_prime(17)); assert!(!is_prime(18)); } #[test] fn test_circle_area() { let area = circle_area(1.0); assert!((area - std::f64::consts::PI).abs() < 1e-10); } } ``` ```rust // src/basic/mod.rs pub mod arithmetic; pub mod compare; ``` ```rust // src/basic/arithmetic.rs pub fn add(a: i32, b: i32) -> i32 { a + b } pub fn sub(a: i32, b: i32) -> i32 { a - b } pub fn mul(a: i32, b: i32) -> i32 { a * b } pub fn div(a: i32, b: i32) -> Option { if b == 0 { None } else { Some(a / b) } } ``` ```rust // src/basic/compare.rs pub fn min(a: i32, b: i32) -> i32 { if a < b { a } else { b } } pub fn max(a: i32, b: i32) -> i32 { if a > b { a } else { b } } pub fn is_even(n: i32) -> bool { n % 2 == 0 } ``` ```rust // src/advanced/mod.rs pub mod stats; pub mod geometry; ``` ```rust // src/advanced/stats.rs pub fn mean(data: &[f64]) -> f64 { let sum: f64 = data.iter().sum(); sum / data.len() as f64 } pub fn median(data: &mut [f64]) -> f64 { data.sort_by(|a, b| a.partial_cmp(b).unwrap()); let mid = data.len() / 2; if data.len() % 2 == 0 { (data[mid - 1] + data[mid]) / 2.0 } else { data[mid] } } pub fn variance(data: &[f64]) -> f64 { let m = mean(data); data.iter().map(|x| (x - m).powi(2)).sum::() / data.len() as f64 } ``` ```rust // src/advanced/geometry.rs use std::f64::consts::PI; pub fn circle_area(radius: f64) -> f64 { PI * radius * radius } pub fn rect_area(width: f64, height: f64) -> f64 { width * height } pub fn triangle_area(base: f64, height: f64) -> f64 { base * height / 2.0 } ``` ```rust // src/utils.rs pub fn is_prime(n: u32) -> bool { if n < 2 { return false; } for i in 2..=((n as f64).sqrt() as u32) { if n % i == 0 { return false; } } true } pub fn factorial(n: u32) -> u64 { (1..=n).fold(1, |acc, x| acc * x as u64) } ``` **4-3 多二进制 Crate Package:** 文件结构: ``` my_app/ ├── Cargo.toml └── src/ ├── lib.rs └── bin/ ├── server.rs └── client.rs ``` ```toml # Cargo.toml [package] name = "my_app" version = "0.1.0" edition = "2021" ``` ```rust // src/lib.rs pub struct Config { pub host: String, pub port: u16, pub debug: bool, } impl Config { pub fn new() -> Config { Config { host: String::from("127.0.0.1"), port: 8080, debug: false, } } } ``` ```rust // src/bin/server.rs use my_app::Config; fn main() { let config = Config::new(); println!("服务器启动于 {}:{}", config.host, config.port); if config.debug { println!("[调试模式] 详细日志已启用"); } } ``` ```rust // src/bin/client.rs use my_app::Config; fn main() { let config = Config::new(); println!("客户端连接到 {}:{}", config.host, config.port); } ``` 运行方式: ``` cargo run --bin server # 启动服务器 cargo run --bin client # 启动客户端 ``` ### 五、综合思考题 **5-1**:在 `inner::deep()` 中访问 `outer::top_level()` 的三种方式: ```rust pub fn deep() { // 方式 1:super(回到父模块 middle,再回到 outer) super::super::top_level(); // 方式 2:crate 绝对路径 crate::outer::top_level(); // 方式 3:self + 多级 super // self::super::super::top_level(); // 等效于 super::super } ``` 若要访问 `another::value()`: ```rust super::super::super::another::value(); // 不够优雅 crate::another::value(); // 推荐:使用 crate 根路径 ``` **5-2**: | 维度 | 方式 A(导入模块) | 方式 B(导入类型) | 方式 C(通配符) | |------|------------------|------------------|----------------| | 清晰度 | 中等(知道来自哪个模块) | 低(看不出来自哪个模块) | 最低(完全不清楚来源) | | 简洁度 | 低(写路径长) | 高(直接使用类型名) | 高 | | 名称冲突风险 | 低 | 中等(可能与其他同名类型冲突) | 高(极易引入未知冲突) | | 适用场景 | 需要明确模块来源时;模块下类型少时 | 高频使用的具体类型 | 测试模块、prelude 模式;生产代码不推荐 | 最佳实践: - 常规代码:使用方式 A(模块导入),调用时写 `collections::HashMap` - 高频类型:使用方式 B - 避免方式 C(除测试模块和 prelude 设计) **5-3**: 虽然 `secret` 标记为 `pub`,但 `inner` 模块本身是**私有的**(`mod inner` 没有 `pub`)。Rust 的可见性是分层级的:父模块定义子模块的可见范围。因为 `inner` 模块对外不可见,即使它内部的项全是 `pub`,外部也无法访问——路径在 `inner` 这一层就已经堵死了。 类比:一个没有挂牌的办公楼(私有模块),即使一楼大堂对所有访客开放(内部函数是 `pub`),路人也找不到入口。 **5-4**: 1. 在 `child` 中调用 `parent_func()`: ```rust super::parent_func(); ``` 2. 在 `sibling` 中调用 `parent_func()`: ```rust crate::parent::parent_func(); ``` 3. `super` 和 `crate` 的区别: - `super`:指向**当前模块的父模块**,适用于在同级模块间或访问父模块内容时使用。 - `crate`:指向**crate 根目录**(即 `lib.rs` 或 `main.rs` 顶层),适用于跨模块树访问时使用绝对路径。 - 场景:父子关系简单、层级少时用 `super`;跨多层级或需要稳定路径时用 `crate`。 **5-5**: **写法 A:内部模块 + 重导出** ```rust mod internal { pub fn helper() {} } pub use internal::helper; ``` - `internal` 模块是私有的,外部不知道它的存在 - 通过 `pub use` 将 `helper` 提升到外层模块的公开 API 中 - 适用于:**内部组织代码但对外隐藏实现细节**。外部调用者只看到 `helper`,不知道它来自 `internal` 模块。后续可以自由重构 `internal` 而不会破坏 API。 **写法 B:公开模块** ```rust pub mod api { pub fn helper() {} } ``` - `api` 模块整体暴露在 API 中 - 外部使用时需要 `api::helper()`,模块结构成为 API 的一部分 - 适用于:**模块结构本身就是设计意图的一部分**,希望用户理解模块层级。但将模块布局暴露后,修改结构可能破坏下游代码。 总结: - 写法 A(`pub use` 重导出):灵活、可卸载、隐藏内部结构;库设计常用模式 - 写法 B(`pub mod`):简单直接、但模块结构成为契约的一部分,重构成本高