Rust的模块系统让你组织和管理代码,防止命名冲突。包(crate)和模块(module)是代码组织的核心概念。本课将深入理解Cargo工作空间、模块可见性、use导入等。
// Rust代码组织层次:
// Workspace → Package → Crate → Module → Item(函数/结构体/等)
//
// Crate: 编译单元,可以是库(lib)或二进制(bin)
// Package: 包含Cargo.toml和一个或多个Crate
// Module: 通过mod关键字组织的代码分组
// 模块定义
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() { println!("添加到等候列表"); }
pub fn seat_at_table() { println!("请入座"); }
}
mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}
fn main() {
// 绝对路径调用
front_of_house::hosting::add_to_waitlist();
// use简化路径
use front_of_house::hosting;
hosting::seat_at_table();
// use as重命名
use front_of_house::hosting::add_to_waitlist as wait;
wait();
}
✅ 验证通过
mod outer {
// 默认私有
fn private_fn() { println!("私有函数"); }
// pub公开
pub fn public_fn() {
println!("公开函数");
private_fn(); // 同模块内可访问私有
}
pub mod inner {
pub fn inner_public() { println!("内部公开"); }
fn inner_private() { println!("内部私有"); }
pub fn access_sibling() {
inner_private(); // 同模块可访问
}
}
pub fn access_inner() {
inner::inner_public(); // 子模块的公开项可访问
// inner::inner_private(); // ❌ 子模块的私有项不可访问
}
}
fn main() {
outer::public_fn();
outer::inner::inner_public();
outer::inner::access_sibling();
outer::access_inner();
}
✅ 验证通过
// 项目结构:
// my_project/
// ├── Cargo.toml
// └── src/
// ├── main.rs ← crate root (binary)
// ├── lib.rs ← library crate root
// ├── config.rs ← mod config;
// └── network/
// ├── mod.rs ← mod network;
// ├── server.rs ← mod network::server;
// └── client.rs ← mod network::client;
// main.rs 或 lib.rs 中声明模块
// mod config;
// mod network;
//
// 这会查找:
// config.rs 或 config/mod.rs
// network/mod.rs
// use的各种形式
// use std::collections::HashMap; // 直接导入
// use std::collections::{HashMap, BTreeMap}; // 批量导入
// use std::collections::*; // 全部导入(不推荐)
// use std::io::{self, Read}; // 自身+子项
# Cargo.toml
[package]
name = "my_app"
version = "0.1.0"
edition = "2024"
[dependencies]
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
anyhow = "1"
[dev-dependencies]
criterion = "0.5" # 只在测试时使用
[profile.release]
opt-level = 3
lto = true
strip = true
// 模拟模块化结构
mod math_utils {
pub fn add(a: i32, b: i32) -> i32 { a + b }
pub fn multiply(a: i32, b: i32) -> i32 { a * b }
pub fn factorial(n: u32) -> u64 {
if n <= 1 { 1 } else { n as u64 * factorial(n - 1) }
}
}
mod string_utils {
pub fn reverse(s: &str) -> String { s.chars().rev().collect() }
pub fn is_palindrome(s: &str) -> bool {
let normalized: String = s.to_lowercase().chars().filter(|c| c.is_alphanumeric()).collect();
normalized == reverse(&normalized)
}
pub fn word_count(s: &str) -> usize {
s.split_whitespace().count()
}
}
mod stats {
pub fn mean(data: &[f64]) -> Option {
if data.is_empty() { return None; }
Some(data.iter().sum::() / data.len() as f64)
}
pub fn median(data: &mut [f64]) -> Option {
if data.is_empty() { return None; }
data.sort_by(|a, b| a.partial_cmp(b).unwrap());
let mid = data.len() / 2;
if data.len() % 2 == 0 {
Some((data[mid - 1] + data[mid]) / 2.0)
} else {
Some(data[mid])
}
}
pub fn stddev(data: &[f64]) -> Option {
let m = mean(data)?;
let variance = data.iter().map(|x| (x - m).powi(2)).sum::() / data.len() as f64;
Some(variance.sqrt())
}
}
fn main() {
use math_utils::*;
use string_utils::*;
use stats::*;
println!("5! = {}", factorial(5));
println!("3 * 7 = {}", multiply(3, 7));
println!("'hello'反转: {}", reverse("hello"));
println!("'racecar'回文: {}", is_palindrome("racecar"));
let mut data = vec![2.5, 3.7, 1.8, 4.2, 3.1, 2.9, 3.5];
println!("均值: {:.2}", mean(&data).unwrap());
println!("中位数: {:.2}", median(&mut data).unwrap());
println!("标准差: {:.2}", stddev(&data).unwrap());
}
✅ 验证通过
用cargo new --lib创建一个库项目,实现3个模块:math、string、io,每个模块至少2个公开函数。
创建Cargo Workspace,包含1个库crate和2个二进制crate,库被两个二进制共享。
使用pub use重导出子模块的项,简化外部使用路径。
// 重导出(pub use)
mod internal {
pub mod math {
pub fn add(a: i32, b: i32) -> i32 { a + b }
pub fn multiply(a: i32, b: i32) -> i32 { a * b }
}
pub mod string {
pub fn reverse(s: &str) -> String { s.chars().rev().collect() }
pub fn capitalize(s: &str) -> String {
let mut c = s.chars();
match c.next() {
None => String::new(),
Some(f) => f.to_uppercase().chain(c).collect(),
}
}
}
}
// 重导出,简化外部访问路径
pub use internal::math;
pub use internal::string;
// 条件编译模块
#[cfg(feature = "network")]
mod network {
pub fn connect(_url: &str) -> String { "connected".into() }
}
fn main() {
// 直接使用重导出的模块
println!("3+5={}", math::add(3, 5));
println!("3*5={}", math::multiply(3, 5));
println!("反转: {}", string::reverse("hello"));
println!("首字母大写: {}", string::capitalize("rust"));
// 文件系统中的模块结构
println!("
模块文件系统约定:");
println!(" mod foo; → 查找 foo.rs 或 foo/mod.rs");
println!(" mod foo::bar; → 查找 foo/bar.rs");
// Cargo workspace
println!("
Workspace结构:");
println!(" Cargo.toml (workspace)");
println!(" crates/core/Cargo.toml");
println!(" crates/server/Cargo.toml");
println!(" crates/cli/Cargo.toml");
}
✅ 验证通过
mod internal {
pub mod math {
pub fn add(a: i32, b: i32) -> i32 { a + b }
pub fn multiply(a: i32, b: i32) -> i32 { a * b }
}
pub mod string_ops {
pub fn reverse(s: &str) -> String { s.chars().rev().collect() }
pub fn capitalize(s: &str) -> String {
let mut c = s.chars();
match c.next() { None => String::new(), Some(f) => f.to_uppercase().chain(c).collect() }
}
}
}
pub use internal::math;
pub use internal::string_ops;
fn main() {
println!("3+5={}", math::add(3, 5));
println!("反转: {}", string_ops::reverse("hello"));
println!("首字母大写: {}", string_ops::capitalize("rust"));
println!("Workspace: Cargo.toml + crates/core + crates/server + crates/cli");
}
✅ 验证通过
// Workspace Cargo.toml:
// [workspace]
// members = ["crates/core", "crates/server", "crates/cli"]
//
// crates/core/Cargo.toml:
// [package]
// name = "myapp-core"
// version = "0.1.0"
//
// crates/server/Cargo.toml:
// [dependencies]
// myapp-core = { path = "../core" }
// axum = "0.8"
//
// crates/cli/Cargo.toml:
// [dependencies]
// myapp-core = { path = "../core" }
// clap = "4"
// Cargo命令
// cargo build - 构建整个workspace
// cargo build -p myapp-cli - 只构建指定crate
// cargo test -p myapp-core - 只测试指定crate
// cargo run -p myapp-cli - 运行指定二进制
fn main() {
println!("Cargo Workspace最佳实践:");
println!(" 1. 共享代码放在core crate");
println!(" 2. 二进制crate依赖core");
println!(" 3. 统一版本管理");
println!(" 4. cargo doc --workspace 生成所有文档");
println!(" 5. CI中只构建修改的crate");
println!("
依赖版本管理:");
println!(" cargo update - 更新所有依赖");
println!(" cargo update -p serde - 只更新serde");
println!(" cargo tree - 查看依赖树");
println!(" cargo tree -d - 查看重复依赖");
println!("
发布流程:");
println!(" 1. cargo test --workspace");
println!(" 2. cargo clippy --workspace");
println!(" 3. cargo doc --workspace");
println!(" 4. cargo publish -p myapp-core");
}
| 类别 | crate | 用途 |
|---|---|---|
| 序列化 | serde | JSON/YAML/TOML/Binary |
| HTTP客户端 | reqwest | 异步HTTP请求 |
| Web框架 | axum | 基于tokio的Web框架 |
| CLI | clap | 命令行参数解析 |
| 日志 | tracing | 结构化日志+追踪 |
| 错误处理 | anyhow/thiserror | 应用/库错误处理 |
| 数据库 | sqlx | 异步SQL+编译期检查 |
| 模板 | tera/askama | HTML模板引擎 |
| 认证 | jsonwebtoken | JWT令牌 |
| 加密 | ring/argon2 | 密码学原语 |
mod validator {
pub fn is_valid_email(email: &str) -> bool {
email.contains('@') && email.contains('.')
}
pub fn is_valid_port(port: u16) -> bool { port > 0 && port < 65536 }
pub fn is_valid_url(url: &str) -> bool {
url.starts_with("http://") || url.starts_with("https://")
}
}
mod config {
use std::collections::HashMap;
use crate::validator;
#[derive(Debug)]
pub struct AppConfig {
pub database_url: String,
pub server_port: u16,
pub api_keys: HashMap,
pub debug: bool,
pub max_connections: usize,
}
impl AppConfig {
pub fn from_env() -> Result {
let database_url = std::env::var("DATABASE_URL")
.unwrap_or_else(|_| "sqlite://default.db".to_string());
if !validator::is_valid_url(&database_url) {
return Err("无效的数据库URL".to_string());
}
let server_port: u16 = std::env::var("PORT")
.unwrap_or_else(|_| "8080".to_string())
.parse().map_err(|_| "无效端口号")?;
if !validator::is_valid_port(server_port) {
return Err("端口号超出范围".to_string());
}
Ok(AppConfig {
database_url, server_port,
api_keys: HashMap::new(),
debug: std::env::var("DEBUG").unwrap_or_default() == "true",
max_connections: std::env::var("MAX_CONN")
.unwrap_or_else(|_| "100".to_string())
.parse().map_err(|_| "无效连接数")?,
})
}
pub fn display(&self) -> String {
format!("数据库: {}\n端口: {}\n调试: {}\n最大连接: {}",
self.database_url, self.server_port, self.debug, self.max_connections)
}
}
}
fn main() {
// 模拟配置加载
println!("应用配置:");
println!(" 数据库URL: sqlite://app.db");
println!(" 端口: 8080");
println!(" 调试模式: false");
println!(" 最大连接: 100");
println!();
println!("邮箱验证:");
println!(" test@example.com: {}", validator::is_valid_email("test@example.com"));
println!(" invalid: {}", validator::is_valid_email("invalid"));
println!();
println!("URL验证:");
println!(" https://api.example.com: {}", validator::is_valid_url("https://api.example.com"));
println!(" ftp://bad.com: {}", validator::is_valid_url("ftp://bad.com"));
}
✅ 验证通过