27 KiB
第四章 结构化工程:模块与包
4.1 模块系统概述
随着项目规模增长,代码组织变得至关重要。Rust的模块系统提供了强大的工具,帮助开发者构建清晰、可维护的代码结构。本章将探索如何使用模块、包和工作空间来组织大型Rust项目。
为什么需要模块化?
模块化设计带来的核心优势:
- 代码组织 - 逻辑相关的代码集中在一起
- 封装 - 隐藏实现细节,只暴露必要接口
- 命名空间 - 避免名称冲突
- 可重用性 - 促进代码复用
- 可测试性 - 更容易为独立模块编写测试
Rust模块系统的核心概念
| 概念 | 描述 | 关键字/文件 |
|---|---|---|
| 模块(Module) | 代码的命名空间单元 | mod |
| 包(Package) | 一个或多个crate的集合 | Cargo.toml |
| Crate | 编译单元,生成库或可执行文件 | lib.rs/main.rs |
| 工作空间(Workspace) | 多个相关包的集合 | [workspace] |
4.2 mod层级设计:构建代码树
模块声明与组织
Rust中的模块可以嵌套,形成树状结构:
// lib.rs
mod front_desk; // 前台模块
mod cataloging; // 编目模块
mod user_services; // 用户服务模块
// 嵌套模块示例
mod user_services {
mod registration {
// 用户注册相关功能
}
mod borrowing {
// 借阅相关功能
}
}
模块文件组织策略
Rust提供两种组织模块的方式:
-
内联模块:在同一文件中定义
// lib.rs mod config { pub const MAX_BOOKS: usize = 5; pub fn get_loan_duration() -> u32 { 14 // 默认借阅期为14天 } } -
文件模块:在单独文件中定义
lib.rs // 声明模块 └── config.rs // 实现模块// lib.rs mod config; // 声明模块,实现在config.rs中 // config.rs pub const MAX_BOOKS: usize = 5; pub fn get_loan_duration() -> u32 { 14 }
子模块文件组织
对于更复杂的模块结构,可以使用目录:
lib.rs // 声明顶层模块
├── user_services.rs // 声明user_services子模块
└── user_services/ // 子模块目录
├── registration.rs
└── borrowing.rs
// user_services.rs
pub mod registration; // 声明子模块
pub mod borrowing; // 声明子模块
模块路径与引用
使用use关键字简化模块路径:
// 不使用use
fn main() {
crate::user_services::registration::register_new_user("Alice");
}
// 使用use
use crate::user_services::registration::register_new_user;
fn main() {
register_new_user("Alice");
}
路径别名:
use crate::user_services::registration::register_new_user as register;
fn main() {
register("Alice");
}
批量导入:
use crate::user_services::registration::{register_new_user, validate_email};
4.3 pub权限控制:接口与实现分离
可见性规则
Rust中的所有项默认是私有的,使用pub关键字使其公开:
mod library {
pub struct Book { // 公开结构体
pub title: String, // 公开字段
isbn: String, // 私有字段
}
impl Book {
pub fn new(title: &str, isbn: &str) -> Self { // 公开方法
Self {
title: title.to_string(),
isbn: isbn.to_string(),
}
}
fn validate_isbn(&self) -> bool { // 私有方法
!self.isbn.is_empty()
}
}
}
可见性级别
Rust提供多种可见性级别:
| 关键字 | 可见范围 | 用途 |
|---|---|---|
| (默认) | 仅当前模块及其子模块 | 隐藏实现细节 |
pub |
任何引入该模块的代码 | 公开API |
pub(crate) |
仅当前crate | 内部API |
pub(super) |
仅父模块 | 限制子模块暴露 |
pub(in path) |
指定路径 | 精细控制可见性 |
示例:
mod library {
pub(crate) struct Catalog { // 仅在crate内可见
// ...
}
pub(super) fn internal_helper() { // 仅对父模块可见
// ...
}
}
接口设计最佳实践
- 最小公开原则:只公开必要的API
- 抽象泄漏控制:使用私有字段防止实现细节泄漏
- API稳定性:谨慎公开可能变化的内容
// 良好的接口设计
pub struct Library {
// 私有实现细节
books: Vec<Book>,
users: HashMap<UserId, User>,
}
impl Library {
// 公开稳定API
pub fn new() -> Self { /* ... */ }
pub fn add_book(&mut self, book: Book) { /* ... */ }
pub fn borrow_book(&mut self, user_id: UserId, book_id: BookId) -> Result<(), BorrowError> { /* ... */ }
// 私有辅助函数
fn find_available_copy(&self, book_id: BookId) -> Option<&Book> { /* ... */ }
}
4.4 workspace多crate管理:扩展到大型项目
工作空间基础
工作空间允许管理多个相关包:
# Cargo.toml (根目录)
[workspace]
members = [
"library-core",
"library-api",
"library-cli"
]
目录结构:
library-workspace/
├── Cargo.toml # 工作空间配置
├── library-core/ # 核心功能crate
├── library-api/ # API服务crate
└── library-cli/ # 命令行工具crate
工作空间依赖管理
工作空间内的crate可以相互依赖:
# library-api/Cargo.toml
[dependencies]
library-core = { path = "../library-core" }
工作空间命令
在工作空间根目录执行命令会应用到所有成员:
# 构建所有crate
cargo build
# 测试特定crate
cargo test -p library-core
# 运行特定crate
cargo run -p library-cli
共享依赖优化
工作空间中的共享依赖只编译一次,提高构建效率:
# 在各crate的Cargo.toml中
[dependencies]
serde = "1.0" # 在多个crate中使用的依赖只编译一次
4.5 文档测试:代码即文档
文档注释类型
Rust支持两种文档注释:
-
外部文档注释:用于项的文档
/// 表示图书馆中的一本书 /// /// # 示例 /// ``` /// let book = Book::new("Rust编程", "978-1234567890"); /// assert_eq!(book.title(), "Rust编程"); /// ``` pub struct Book { // ... } -
内部文档注释:用于模块或crate整体文档
//! # 图书馆管理系统 //! //! 这个模块提供图书馆管理的核心功能,包括: //! - 图书编目 //! - 用户管理 //! - 借阅流程
文档测试
文档中的代码块默认会作为测试运行:
/// 计算借阅的逾期费用
///
/// # 参数
/// * `days_overdue` - 逾期天数
///
/// # 返回值
/// 应付的逾期费用(元)
///
/// # 示例
/// ```
/// use library::calculate_overdue_fee;
/// assert_eq!(calculate_overdue_fee(5), 5.0); // 5天逾期,收费5元
/// assert_eq!(calculate_overdue_fee(0), 0.0); // 未逾期,无费用
/// ```
pub fn calculate_overdue_fee(days_overdue: u32) -> f64 {
days_overdue as f64
}
运行文档测试:
cargo test --doc
文档测试特殊标记
控制文档测试行为:
/// ```
/// # use library::Book; // 这行在文档中隐藏,但测试时执行
/// let book = Book::new("Rust编程", "978-1234567890");
/// ```
///
/// ```no_run
/// // 编译但不运行的代码
/// let book = fetch_from_database("978-1234567890");
/// ```
///
/// ```compile_fail
/// // 应该编译失败的代码
/// let book: Book = "不是书";
/// ```
///
/// ```ignore
/// // 完全忽略的代码
/// let x = 非法语法;
/// ```
4.6 实例项目:图书馆管理系统
让我们应用所学知识,构建一个模块化的图书馆管理系统。
项目结构设计
library/
├── Cargo.toml
└── src/
├── lib.rs # 主模块和公共API
├── models/ # 数据模型
│ ├── mod.rs
│ ├── book.rs
│ └── user.rs
├── services/ # 业务逻辑
│ ├── mod.rs
│ ├── catalog.rs
│ └── lending.rs
└── utils/ # 工具函数
├── mod.rs
└── validation.rs
实现核心模块
1. 主模块 (lib.rs)
//! # 图书馆管理系统
//!
//! 一个模块化的图书馆管理系统,提供图书编目、用户管理和借阅服务。
pub mod models;
pub mod services;
mod utils; // 内部工具模块,不对外暴露
// 重新导出核心类型,简化用户导入
pub use models::{Book, User};
pub use services::{catalog::Catalog, lending::LendingService};
/// 系统版本号
pub const VERSION: &str = "0.1.0";
/// 创建一个新的图书馆实例
pub fn new_library() -> services::Library {
services::Library::new()
}
2. 模型模块 (models/mod.rs)
//! 系统中使用的数据模型
pub mod book;
pub mod user;
pub use book::Book;
pub use user::User;
3. 图书模型 (models/book.rs)
//! 图书相关的数据模型
use std::fmt;
/// 表示图书馆中的一本书
#[derive(Debug, Clone, PartialEq)]
pub struct Book {
title: String,
author: String,
isbn: String,
available: bool,
}
impl Book {
/// 创建一本新书
///
/// # 示例
/// ```
/// use library::Book;
/// let book = Book::new("Rust编程艺术", "张三", "978-1234567890");
/// assert_eq!(book.title(), "Rust编程艺术");
/// assert!(book.is_available());
/// ```
pub fn new(title: &str, author: &str, isbn: &str) -> Self {
Self {
title: title.to_string(),
author: author.to_string(),
isbn: isbn.to_string(),
available: true,
}
}
/// 获取书名
pub fn title(&self) -> &str {
&self.title
}
/// 获取作者
pub fn author(&self) -> &str {
&self.author
}
/// 获取ISBN
pub fn isbn(&self) -> &str {
&self.isbn
}
/// 检查书是否可借
pub fn is_available(&self) -> bool {
self.available
}
/// 标记为已借出
pub(crate) fn mark_borrowed(&mut self) {
self.available = false;
}
/// 标记为已归还
pub(crate) fn mark_returned(&mut self) {
self.available = true;
}
}
impl fmt::Display for Book {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} by {} (ISBN: {})", self.title, self.author, self.isbn)
}
}
**4. 用户模型 (models/user.rs)**
```rust
//! 用户相关的数据模型
use std::fmt;
/// 用户ID类型
pub type UserId = u32;
/// 表示图书馆的一名用户
#[derive(Debug, Clone, PartialEq)]
pub struct User {
id: UserId,
name: String,
email: String,
active: bool,
borrowed_books: Vec<String>, // 存储已借阅书籍的ISBN
}
impl User {
/// 创建一个新用户
///
/// # 示例
/// ```
/// use library::User;
/// let user = User::new(1, "李四", "lisi@example.com");
/// assert_eq!(user.name(), "李四");
/// assert!(user.is_active());
/// ```
pub fn new(id: UserId, name: &str, email: &str) -> Self {
Self {
id,
name: name.to_string(),
email: email.to_string(),
active: true,
borrowed_books: Vec::new(),
}
}
/// 获取用户ID
pub fn id(&self) -> UserId {
self.id
}
/// 获取用户名
pub fn name(&self) -> &str {
&self.name
}
/// 获取用户邮箱
pub fn email(&self) -> &str {
&self.email
}
/// 检查用户是否激活
pub fn is_active(&self) -> bool {
self.active
}
/// 获取用户已借阅的书籍ISBN列表
pub fn borrowed_books(&self) -> &[String] {
&self.borrowed_books
}
/// 记录用户借阅了一本书
pub(crate) fn borrow_book(&mut self, isbn: &str) {
self.borrowed_books.push(isbn.to_string());
}
/// 记录用户归还了一本书
pub(crate) fn return_book(&mut self, isbn: &str) -> bool {
if let Some(pos) = self.borrowed_books.iter().position(|b| b == isbn) {
self.borrowed_books.remove(pos);
true
} else {
false
}
}
/// 停用用户账户
pub(crate) fn deactivate(&mut self) {
self.active = false;
}
/// 重新激活用户账户
pub(crate) fn activate(&mut self) {
self.active = true;
}
}
impl fmt::Display for User {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} (ID: {}, Email: {})", self.name, self.id, self.email)
}
}
5. 服务模块 (services/mod.rs)
//! 图书馆业务服务模块
pub mod catalog;
pub mod lending;
use std::collections::HashMap;
use crate::models::{Book, User, UserId};
/// 图书馆主服务
pub struct Library {
catalog: catalog::Catalog,
lending: lending::LendingService,
}
impl Library {
/// 创建一个新的图书馆实例
pub fn new() -> Self {
Self {
catalog: catalog::Catalog::new(),
lending: lending::LendingService::new(),
}
}
/// 获取目录服务
pub fn catalog(&self) -> &catalog::Catalog {
&self.catalog
}
/// 获取可变目录服务
pub fn catalog_mut(&mut self) -> &mut catalog::Catalog {
&mut self.catalog
}
/// 获取借阅服务
pub fn lending(&self) -> &lending::LendingService {
&self.lending
}
/// 获取可变借阅服务
pub fn lending_mut(&mut self) -> &mut lending::LendingService {
&mut self.lending
}
}
impl Default for Library {
fn default() -> Self {
Self::new()
}
}
6. 目录服务 (services/catalog.rs)
//! 图书目录管理服务
use std::collections::HashMap;
use crate::models::Book;
use crate::utils::validation;
/// 图书目录错误类型
#[derive(Debug)]
pub enum CatalogError {
/// ISBN已存在
DuplicateIsbn(String),
/// ISBN不存在
IsbnNotFound(String),
/// ISBN格式无效
InvalidIsbn(String),
}
/// 图书目录服务
pub struct Catalog {
books: HashMap<String, Book>,
}
impl Catalog {
/// 创建一个新的目录服务
pub fn new() -> Self {
Self {
books: HashMap::new(),
}
}
/// 添加一本新书到目录
///
/// # 错误
/// 如果ISBN已存在或无效,返回错误
///
/// # 示例
/// ```
/// use library::{Book, services::catalog::Catalog};
///
/// let mut catalog = Catalog::new();
/// let book = Book::new("Rust编程", "张三", "978-1234567890");
///
/// // 首次添加成功
/// assert!(catalog.add_book(book.clone()).is_ok());
///
/// // 重复添加失败
/// assert!(catalog.add_book(book).is_err());
/// ```
pub fn add_book(&mut self, book: Book) -> Result<(), CatalogError> {
let isbn = book.isbn();
// 验证ISBN格式
if !validation::is_valid_isbn(isbn) {
return Err(CatalogError::InvalidIsbn(isbn.to_string()));
}
// 检查ISBN是否已存在
if self.books.contains_key(isbn) {
return Err(CatalogError::DuplicateIsbn(isbn.to_string()));
}
// 添加图书
self.books.insert(isbn.to_string(), book);
Ok(())
}
/// 根据ISBN查找图书
pub fn find_by_isbn(&self, isbn: &str) -> Option<&Book> {
self.books.get(isbn)
}
/// 根据ISBN查找可变图书引用
pub(crate) fn find_by_isbn_mut(&mut self, isbn: &str) -> Option<&mut Book> {
self.books.get_mut(isbn)
}
/// 根据标题查找图书
pub fn find_by_title(&self, title: &str) -> Vec<&Book> {
self.books.values()
.filter(|book| book.title().contains(title))
.collect()
}
/// 根据作者查找图书
pub fn find_by_author(&self, author: &str) -> Vec<&Book> {
self.books.values()
.filter(|book| book.author().contains(author))
.collect()
}
/// 获取所有图书
pub fn all_books(&self) -> Vec<&Book> {
self.books.values().collect()
}
/// 获取可用图书数量
pub fn available_count(&self) -> usize {
self.books.values()
.filter(|book| book.is_available())
.count()
}
/// 获取总图书数量
pub fn total_count(&self) -> usize {
self.books.len()
}
}
impl Default for Catalog {
fn default() -> Self {
Self::new()
}
}
7. 借阅服务 (services/lending.rs)
//! 图书借阅管理服务
use std::collections::HashMap;
use crate::models::{Book, User, UserId};
use crate::services::catalog::Catalog;
/// 借阅记录
#[derive(Debug)]
pub struct LoanRecord {
user_id: UserId,
isbn: String,
loan_date: chrono::DateTime<chrono::Utc>,
due_date: chrono::DateTime<chrono::Utc>,
}
/// 借阅错误类型
#[derive(Debug)]
pub enum LendingError {
/// 用户不存在
UserNotFound(UserId),
/// 图书不存在
BookNotFound(String),
/// 图书不可用(已借出)
BookUnavailable(String),
/// 用户账户未激活
UserInactive(UserId),
/// 用户已达到最大借阅限制
BorrowLimitReached(UserId),
/// 借阅记录不存在
LoanNotFound,
}
/// 借阅服务
pub struct LendingService {
users: HashMap<UserId, User>,
active_loans: Vec<LoanRecord>,
max_loans_per_user: usize,
loan_duration_days: i64,
}
impl LendingService {
/// 创建一个新的借阅服务
pub fn new() -> Self {
Self {
users: HashMap::new(),
active_loans: Vec::new(),
max_loans_per_user: 5,
loan_duration_days: 14,
}
}
/// 设置每位用户的最大借阅数量
pub fn set_max_loans_per_user(&mut self, max: usize) {
self.max_loans_per_user = max;
}
/// 设置借阅期限(天数)
pub fn set_loan_duration(&mut self, days: i64) {
self.loan_duration_days = days;
}
/// 添加用户
pub fn add_user(&mut self, user: User) {
self.users.insert(user.id(), user);
}
/// 查找用户
pub fn find_user(&self, user_id: UserId) -> Option<&User> {
self.users.get(&user_id)
}
/// 查找可变用户引用
fn find_user_mut(&mut self, user_id: UserId) -> Option<&mut User> {
self.users.get_mut(&user_id)
}
/// 借阅图书
pub fn borrow_book(
&mut self,
user_id: UserId,
isbn: &str,
catalog: &mut Catalog
) -> Result<(), LendingError> {
// 检查用户是否存在
let user = self.find_user_mut(user_id)
.ok_or(LendingError::UserNotFound(user_id))?;
// 检查用户是否激活
if !user.is_active() {
return Err(LendingError::UserInactive(user_id));
}
// 检查用户是否达到借阅上限
if user.borrowed_books().len() >= self.max_loans_per_user {
return Err(LendingError::BorrowLimitReached(user_id));
}
// 检查图书是否存在并可借
let book = catalog.find_by_isbn_mut(isbn)
.ok_or_else(|| LendingError::BookNotFound(isbn.to_string()))?;
if !book.is_available() {
return Err(LendingError::BookUnavailable(isbn.to_string()));
}
// 更新图书状态
book.mark_borrowed();
// 更新用户借阅记录
user.borrow_book(isbn);
// 创建借阅记录
let now = chrono::Utc::now();
let due_date = now + chrono::Duration::days(self.loan_duration_days);
self.active_loans.push(LoanRecord {
user_id,
isbn: isbn.to_string(),
loan_date: now,
due_date,
});
Ok(())
}
/// 归还图书
pub fn return_book(
&mut self,
user_id: UserId,
isbn: &str,
catalog: &mut Catalog
) -> Result<(), LendingError> {
// 检查用户是否存在
let user = self.find_user_mut(user_id)
.ok_or(LendingError::UserNotFound(user_id))?;
// 检查图书是否存在
let book = catalog.find_by_isbn_mut(isbn)
.ok_or_else(|| LendingError::BookNotFound(isbn.to_string()))?;
// 更新用户借阅记录
if !user.return_book(isbn) {
return Err(LendingError::LoanNotFound);
}
// 更新图书状态
book.mark_returned();
// 移除借阅记录
let loan_index = self.active_loans.iter()
.position(|loan| loan.user_id == user_id && loan.isbn == isbn)
.ok_or(LendingError::LoanNotFound)?;
self.active_loans.remove(loan_index);
Ok(())
}
/// 获取用户的所有借阅
pub fn get_user_loans(&self, user_id: UserId) -> Vec<&LoanRecord> {
self.active_loans.iter()
.filter(|loan| loan.user_id == user_id)
.collect()
}
/// 获取所有逾期借阅
pub fn get_overdue_loans(&self) -> Vec<&LoanRecord> {
let now = chrono::Utc::now();
self.active_loans.iter()
.filter(|loan| loan.due_date < now)
.collect()
}
}
impl Default for LendingService {
fn default() -> Self {
Self::new()
}
}
8. 工具模块 (utils/mod.rs)
//! 内部工具函数
pub mod validation;
9. 验证工具 (utils/validation.rs)
//! 数据验证工具
/// 检查ISBN是否有效
///
/// 简化版实现,仅检查基本格式
pub fn is_valid_isbn(isbn: &str) -> bool {
// 移除所有连字符和空格
let isbn = isbn.replace(['-', ' '], "");
// ISBN-13应为13位数字
if isbn.len() != 13 {
return false;
}
// 检查是否全为数字
isbn.chars().all(|c| c.is_ascii_digit())
}
/// 检查邮箱格式是否有效
pub fn is_valid_email(email: &str) -> bool {
// 简化版邮箱验证
email.contains('@') && email.split('@').count() == 2
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid_isbn() {
assert!(is_valid_isbn("978-1234567890"));
assert!(is_valid_isbn("9781234567890"));
}
#[test]
fn test_invalid_isbn() {
assert!(!is_valid_isbn("978-12345")); // 太短
assert!(!is_valid_isbn("978-1234567890X")); // 包含非数字
}
#[test]
fn test_valid_email() {
assert!(is_valid_email("user@example.com"));
}
#[test]
fn test_invalid_email() {
assert!(!is_valid_email("user@"));
assert!(!is_valid_email("user"));
assert!(!is_valid_email("user@domain@example"));
}
}
示例应用程序
让我们创建一个简单的命令行应用程序,展示如何使用我们的图书馆管理系统:
10. 主程序 (main.rs)
//! 图书馆管理系统示例应用
use library::{Book, User, new_library};
fn main() {
println!("=== 图书馆管理系统 ===");
// 创建图书馆实例
let mut library = new_library();
// 添加图书
let books = [
Book::new("Rust编程艺术", "张三", "978-1234567890"),
Book::new("系统设计实践", "李四", "978-0987654321"),
Book::new("数据结构与算法", "王五", "978-5432109876"),
];
for book in &books {
match library.catalog_mut().add_book(book.clone()) {
Ok(_) => println!("添加图书: {}", book),
Err(e) => println!("添加图书失败: {:?}", e),
}
}
// 添加用户
let users = [
User::new(1, "赵六", "zhaoliu@example.com"),
User::new(2, "钱七", "qianqi@example.com"),
];
for user in &users {
library.lending_mut().add_user(user.clone());
println!("添加用户: {}", user);
}
// 借阅图书
let user_id = 1;
let isbn = "978-1234567890";
match library.lending_mut().borrow_book(user_id, isbn, library.catalog_mut()) {
Ok(_) => println!("用户 {} 成功借阅图书 {}", user_id, isbn),
Err(e) => println!("借阅失败: {:?}", e),
}
// 查看用户借阅情况
if let Some(user) = library.lending().find_user(user_id) {
println!("用户 {} 已借阅的图书:", user.name());
for isbn in user.borrowed_books() {
if let Some(book) = library.catalog().find_by_isbn(isbn) {
println!(" - {}", book);
}
}
}
// 归还图书
match library.lending_mut().return_book(user_id, isbn, library.catalog_mut()) {
Ok(_) => println!("用户 {} 成功归还图书 {}", user_id, isbn),
Err(e) => println!("归还失败: {:?}", e),
}
// 查看图书馆统计信息
println!("\n=== 图书馆统计 ===");
println!("总图书数: {}", library.catalog().total_count());
println!("可借图书数: {}", library.catalog().available_count());
}
项目配置
11. 包配置 (Cargo.toml)
[package]
name = "library"
version = "0.1.0"
edition = "2021"
authors = ["Your Name <your.email@example.com>"]
description = "A modular library management system"
[dependencies]
chrono = "0.4"
[dev-dependencies]
criterion = "0.5"
[lib]
name = "library"
path = "src/lib.rs"
[[bin]]
name = "library-cli"
path = "src/main.rs"
4.7 总结
在本章中,我们探索了Rust的模块系统,学习了如何组织和结构化大型项目。我们讨论了以下关键概念:
- 模块层级设计:使用
mod关键字创建模块树,通过文件系统组织代码 - 可见性控制:使用
pub及其变体控制API的暴露范围 - 工作空间管理:使用工作空间组织多个相关crate
- 文档测试:编写可执行的文档,确保代码示例始终有效
通过图书馆管理系统的实例项目,我们实践了这些概念,构建了一个模块化、可维护的系统。这种结构化方法不仅提高了代码的可读性和可维护性,还促进了团队协作和代码重用。
关键要点回顾
- 使用模块组织相关功能,形成清晰的代码结构
- 遵循"最小公开原则",只暴露必要的API
- 利用文件系统组织模块,使代码结构直观
- 使用工作空间管理大型项目中的多个crate
- 编写文档测试,确保文档与代码同步
实践建议
- 模块设计:先设计模块结构,再编写实现代码
- API设计:谨慎考虑哪些项应该公开,哪些应该保持私有
- 文档优先:编写文档和测试,然后实现功能
- 渐进式重构:随着项目增长,不断调整模块结构
在下一章中,我们将探索Rust的并发安全特性,学习如何利用所有权系统编写高效、安全的并发代码。