“文字地牢”小游戏通关 Rust 入门-模块化与可见性
·
模块化与可见性
上文我们大致了解了"文字地牢"小游戏的存档与读档,那么我们本章的目标是理解 crate、模块与路径;掌握 use、pub、相对/绝对路径;构建清晰的 API 边界。
基本概念
Crate
Crate是Rust中的编译单元,可以是一个二进制程序或一个库。每个Rust项目至少包含一个crate。
Crate的类型:
- 二进制crate:可执行程序,必须有
main函数 - 库crate:可被其他crate使用的库,提供API供调用
Crate的组织:
- 根模块:每个crate都有一个根模块,其他模块都挂载在根模块下
- 包(Package):包含一个或多个crate的Cargo项目
- 工作区(Workspace):包含多个相关包的Cargo项目集合
模块(Module)
模块是Rust中组织代码的方式,允许我们将代码分组并控制其可见性。
模块的功能:
- 组织代码:将相关的项组织在一起
- 控制可见性:通过
pub关键字控制项的可见性 - 避免命名冲突:为项提供命名空间
- 封装实现细节:隐藏内部实现,只暴露必要的接口
模块的定义方式:
- 文件模块:单个文件定义模块
- 目录模块:目录结构定义模块,使用
mod.rs或同名文件
路径(Path)
路径用于引用模块中的项,可以是绝对路径或相对路径。
路径类型:
- 绝对路径:从crate根开始的完整路径,使用
crate::前缀 - 相对路径:从当前模块开始的路径,使用
self::或super::
路径关键字:
- crate:crate根模块
- self:当前模块
- super:父模块
可见性(Visibility)
Rust通过可见性控制来封装实现细节,只暴露必要的接口给外部使用。
可见性级别:
- 私有(默认):只能在定义的模块内访问
- pub:公共的,可在任何地方访问
- pub(crate):在整个crate内可见
- pub(super):在父模块中可见
- pub(in path):在指定路径内可见
如何使用
模块定义和组织
// 在main.rs或lib.rs中定义模块
mod game;
mod map;
mod io;
mod errors;
// 在单独的文件中定义模块内容
// game/mod.rs
pub mod rendering;
mod movement;
// 嵌套模块
mod game {
pub mod state;
mod ai;
mod combat {
pub fn attack() { }
fn defend() { }
}
}
路径引用
// 绝对路径引用
use crate::game::Player;
use crate::map::Tile;
// 相对路径引用
use super::errors::AppError;
use self::combat::attack;
// 重新导出
pub use game::Player;
pub use map::{Map, Tile};
// 重命名导入
use std::collections::HashMap as Map;
use game::Player as GamePlayer;
// 嵌套路径
use std::{
collections::{HashMap, HashSet},
io::{Read, Write},
path::Path,
};
可见性控制
// 私有项(默认)
fn internal_helper() { }
// 公共项
pub fn public_api() { }
// crate内可见
pub(crate) fn crate_internal() { }
// 父模块可见
pub(super) fn parent_visible() { }
// 指定路径可见
pub(in crate::game) fn game_internal() { }
// 结构体的可见性
pub struct Player {
pub name: String, // 公共字段
health: i32, // 私有字段
}
impl Player {
// 关联函数的可见性
pub fn new(name: String) -> Self {
Player { name, health: 100 }
}
// 私有关联函数
fn heal(&mut self, amount: i32) {
self.health += amount;
}
}
模块与路径
- 顶层:
mod game; mod map; mod io; mod errors;。 - 路径:
- 绝对:
crate::game::Game; - 相对:
super::/self::导航子模块。
- 绝对:
可见性与 API 设计
pub对外暴露;pub(crate)在当前 crate 内可见;默认私有。- 保持内部不变式与封装,避免外部直接操作内部细节(如
tiles)。
注意事项
- 合理组织模块结构,避免过深的嵌套。
- 谨慎使用
pub关键字,只暴露必要的接口。 - 使用
use语句简化路径引用,但要避免命名冲突。 - 在大型项目中,考虑将相关功能组织在同一个模块中。
- 避免使用全局
use *,这会增加命名污染的风险。 - 使用模块来表达代码的逻辑结构,而不是随意分组。
- 为公共API提供文档注释。
- 考虑使用
pub use来创建门面模式,简化外部使用。
本项目中的使用
在我们的项目中,我们按照功能将代码组织成不同的模块:
mod game;
mod map;
mod io;
mod errors;
每个模块都有其特定的职责:
game模块:处理游戏逻辑和状态map模块:处理地图数据结构io模块:处理输入输出操作errors模块:定义错误类型
我们使用pub关键字来控制模块中项的可见性,例如:
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Player {
pub position: Position,
pub hp: i32,
}
在模块间引用时,我们使用路径:
use crate::game::{Game, GameState, Player, Position};
模块结构优化建议
在地牢探险游戏中,我们可以进一步优化模块结构:
- 分层模块组织:
// main.rs
mod core;
mod entities;
mod systems;
mod utils;
// core/mod.rs
pub mod game_state;
pub mod engine;
// entities/mod.rs
pub mod player;
pub mod enemy;
pub mod item;
// systems/mod.rs
pub mod rendering;
pub mod input;
pub mod combat;
- 门面模式:
// lib.rs
pub mod prelude {
pub use crate::entities::player::Player;
pub use crate::core::game_state::GameState;
pub use crate::systems::rendering::render;
}
- 内部模块:
// map/mod.rs
mod generation;
mod validation;
pub use generation::generate_dungeon;
pub use validation::is_valid_position;
// 只在map模块内部使用
fn internal_helper() { }
模块设计最佳实践
- 单一职责原则:每个模块应该有明确的职责
- 高内聚低耦合:模块内部高度相关,模块间依赖最小
- 稳定的API:公共接口应该稳定,避免频繁变更
- 文档化:为公共API提供清晰的文档
- 测试友好:设计易于测试的模块结构
高级模块技术
条件编译模块
#[cfg(feature = "debug")]
mod debug_tools {
pub fn debug_render() { }
}
#[cfg(test)]
mod tests {
#[test]
fn test_module_functionality() { }
}
模块重构技巧
// 重构前
mod old_structure {
pub fn process_player() { }
pub fn process_enemy() { }
pub fn process_item() { }
}
// 重构后
mod entities {
pub mod player {
pub fn process() { }
}
pub mod enemy {
pub fn process() { }
}
pub mod item {
pub fn process() { }
}
}
练习:
- 将随机生成逻辑放入
map::gen内部模块,并仅暴露高层 API。 - 用
pub(crate)控制模块内实用函数的可见性。
概念补充
- crate 边界:一个包可包含多个 crate;二进制 crate 作为入口,库 crate 提供复用 API。
- 可见性细粒度:
pub(super)暴露给父模块;pub(in path)仅对特定路径可见。 - 组织建议:按"领域模块"而非"技术层(utils)"组织;顶层只导出稳定 API;内部模块可保留演进空间。
- 重导出:
pub use作为门面(facade)统一对外 API;避免外部依赖内部深层路径。 - 命名冲突:
use foo as bar做别名;谨慎使用全局use *,降低命名污染。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)