Rust: The Rust Module System and Cargo
Last updated: 2026-08-26
The module system is Rust's "code addressing scheme"—much like a building's street address, it allows you to pinpoint the location of every piece of code and control which parts of the code can be accessed from outside.
If a large project were a city, then modules (mods) would be neighborhoods, files would be buildings, and functions would be rooms. Cargo is the city administration—responsible for building roads, performing maintenance, and ensuring quality. Without a module system, the code would be a jumble of "urban villages."
1. What You'll Learn
modKeyword Definition Modules and Nested ModulespubVisibility Control—Access Rules for Parent, Child, and Sibling ModulesusePath Import andsuper/crateRelative PathsCargo.tomlDependency Management and Semantic Versioning (SemVer)cargo build/test/bench/docCommon commands- Workspace multi-package management and the division of labor between
lib.rsandmain.rs
2. The Story Behind the Apartment Numbering System
(1) Suffering: A City Without House Numbers
Tom moved into a newly built apartment building and discovered that it didn't have a house numbering system.
- He was looking for Room 502 in Building 3, but every building looked the same.
- When delivering food, delivery drivers have to call and ask, "Which building are you in?"
- Property Management Notice: "Please come down to pick up your package, residents of Unit 3, 5th Floor" — but there are actually six households on the 5th floor of Unit 3.
- To make matters worse, the new residents changed their house number to "Alibaba"—and the entire addressing system collapsed.
"It would be great if there were a standardized house numbering system: building-unit-apartment..."
(2) Approaches to the Rust Module System
Apartment(Crate) → A building
Building Name(crate name) → Building Number
Unit(Module) → Apartment Building Entrance
Room Number(Function) → Specific Rooms
// File Structure Correspondence:
// src/
// main.rs → Apartment Lobby(Entrance)
// building/
// mod.rs → Building Information
// unit_1/
// mod.rs → 1 Unit
// room_501.rs → 501 Room
// room_502.rs → 502 Room
// In Rust, through mod and pub, precisely control who can access what
mod building {
pub mod unit_1 {
pub fn room_501() -> &'static str {
"501 Room: Tom Home"
}
fn room_502() -> &'static str {
"502 Room: Private Space" // Default: Private, not visible externally
}
}
}
fn main() {
// Access via the full path
println!("{}", building::unit_1::room_501());
// println!("{}", building::unit_1::room_502()); // ❌ Private Functions,Compilation Error
}
Rust's module system is like an apartment building's address system:
craterepresents the entire building,modrepresents the unit, andfnrepresents the apartment.pubcontrols which apartments have doors opening to the outside; apartments withoutpubare private—outsiders cannot enter them freely.
3. Core Concepts
(1) Module System and Paths
graph TB
A[Rust Modular System] --> B[mod Definition]
A --> C[pub Visibility]
A --> D[use Path Import]
A --> E[Cargo Project Management]
B --> B1["mod Module Name { ... }"]
B --> B2["mod Module Name; // From a file"]
C --> C1["pub: Visible to the public"]
C --> C2["pub(crate): crate only, visible inside"]
C --> C3["pub(super): Visible only to the parent module"]
C --> C4["No pub: Private"]
D --> D1["use crate::a::b::c;"]
D --> D2["use super::module;"]
D --> D3["use self::module;"]
E --> E1["Cargo.toml Dependency"]
E --> E2["cargo build / test"]
E --> E3["workspace Multiple Packages"]
E --> E4["lib.rs vs main.rs"]
(2) Comparison of Visibility Rules
| Visibility | Keywords | Who Can Access | Analogy |
|---|---|---|---|
| Private | None (default) | Current module and submodules | Only family members can enter the bedroom |
| Visible to Parent Module | pub(super) |
Parent Module | Neighbors upstairs and downstairs can drop by |
| Visible within the crate | pub(crate) |
All modules in the current crate | Residents can enter the community gate |
| Public | pub |
All external crates | Anyone can enter the mall |
(3) Path Types
| Path Type | Prefix | Example | Description |
|---|---|---|---|
| Absolute Path | crate:: |
crate::utils::helper::foo |
Starting from the crate root |
| Relative Path | self:: |
self::helper::foo |
Starting from the current module |
| Relative Path | super:: |
super::helper::foo |
Starting from the parent module |
| External Path | Package Name | serde::Serialize |
Starting from an external crate |
(4) Quick Reference for Common Cargo Commands
| Command | Function | Common Options |
|---|---|---|
cargo new |
Create a New Project | --lib (Library Project) |
cargo build |
Compile Project | --release (Optimized Compilation) |
cargo run |
Compile and run | --bin name (specify binary) |
cargo check |
Quickly check for compilation errors | Faster than a build; does not generate binaries |
cargo test |
Run Test | test_name (Specified Test) |
cargo doc |
Generate Document | --open (Opens browser automatically) |
cargo clippy |
Code lint checks | -W clippy::all |
cargo fmt |
Code Formatting | --check (Check only, do not modify) |
cargo add |
Add Dependency | --features xxx |
cargo update |
Update the dependency lock file | Update Cargo.lock |
cargo publish |
Publish to crates.io | Must log in first |
cargo clean |
Clean up build artifacts | Delete the target/ directory |
4. Modules and Cargo Examples
▶ Example 1: Module Definitions and pub Visibility (Difficulty ⭐)
Output:
<dish>
Dishes: <menu_item.get_price()>, Price: <menu_item.name> yuan
Chef Information: <restaurant::prepare_in_kitchen("Kung Pao Chicken")>
Price: <menu_item.price>
// ============================================
// Module Nesting、pub Visibility、Path Access
// Demo: The restaurant's kitchen is not visible to customers, but visible to servers
// ============================================
// Defining the Restaurant Module
mod restaurant {
// Public: Customers may enter the restaurant
pub struct Menu {
pub name: String,
price: f64, // Default: Private,Not visible externally
}
impl Menu {
// Public Constructor
pub fn new(name: &str, price: f64) -> Menu {
Menu {
name: name.to_string(),
price,
}
}
// Public Methods: Get Price
pub fn get_price(&self) -> f64 {
self.price
}
}
// Public: Customers can order food
pub fn order_food(item: &str) -> String {
// Private: Kitchen operations are not visible to customers
let prepared = prepare_in_kitchen(item);
format!("Your {} Ready: {}", item, prepared)
}
// Private: Customers are not allowed in the kitchen.
fn prepare_in_kitchen(item: &str) -> String {
format!("[Kitchen] {} Cooking in progress...", item)
}
// Nested Modules: Inside the Kitchen
mod kitchen {
// Private Storage Area
pub struct Storage {
pub items: Vec<String>,
}
impl Storage {
pub fn new() -> Storage {
Storage {
items: vec![
"Vegetables".to_string(),
"Meat".to_string(),
"Seasonings".to_string(),
],
}
}
}
}
}
fn main() {
// Accessing Public Module Members
let dish = restaurant::order_food("Kung Pao Chicken");
println!("{}", dish);
// Create a public struct
let menu_item = restaurant::Menu::new("Kung Pao Chicken", 38.0);
println!("Dishes: {}, Price: {:.1} yuan", menu_item.name, menu_item.get_price());
// The following code cannot be compiled(Uncomment this line to try it):
// println!("Chef Information: {}", restaurant::prepare_in_kitchen("Kung Pao Chicken")); // ❌ Private Functions
// println!("Price: {}", menu_item.price); // ❌ Private Fields
// let storage = restaurant::kitchen::Storage::new(); // ❌ kitchen The module is private.
}
Output:
Your Kung Pao Chicken Ready: [Kitchen] Kung Pao Chicken Cooking in progress...
Dishes: Kung Pao Chicken, Price: 38.0 yuan
Module visibility rules are like the physical layout of a restaurant: customers (external code) can only enter the dining room (
pubmodule) and cannot enter the kitchen (private modules). The operations taking place in the kitchen (prepare_in_kitchen) are completely invisible to the outside world—this is encapsulation.
▶ Example 2: use paths and super/crate (Difficulty: ⭐⭐)
Output:
<company::engineering::frontend::full_info()>
<frontend::full_info()>
<backend::full_info()>
Number of employees in the Marketing Department: <marketing::member_count()>
Total Number of Employees: <marketing::total_employees()>
Department: <eng::team_name()>
// ============================================
// use Keyword Import Path、super and crate Relative Path
// Simulation: Company Organizational Structure - Department→Group→Employees
// ============================================
// Top-Level Module: Company
mod company {
// Engineering Department
pub mod engineering {
pub fn team_name() -> &'static str {
"Engineering Department"
}
// Front-End Team
pub mod frontend {
pub fn member_count() -> u32 {
5
}
// Use super to access the parent module (engineering)
pub fn full_info() -> String {
format!("{} Front-End Team, {} people", super::team_name(), member_count())
}
}
// Backend Team
pub mod backend {
pub fn member_count() -> u32 {
8
}
// Usage super Access the Parent Module
pub fn full_info() -> String {
format!("{} Backend Team, {} people", super::team_name(), member_count())
}
}
}
// Marketing Department
pub mod marketing {
pub fn team_name() -> &'static str {
"Marketing Department"
}
// Usage crate Path Access from the Root
pub fn total_employees() -> u32 {
// From crate root, access begins
crate::company::engineering::frontend::member_count()
+ crate::company::engineering::backend::member_count()
+ self::member_count()
}
fn member_count() -> u32 {
6
}
}
}
// Usage use Import Path——Simplify the call
use company::engineering::frontend;
use company::engineering::backend;
use company::marketing;
fn main() {
// Method 1: Full path (Not recommended, too long to write)
println!("{}", company::engineering::frontend::full_info());
// Method 2: Call directly after use import (Recommended)
println!("{}", frontend::full_info());
println!("{}", backend::full_info());
// Introduction marketing Module
println!("Number of employees in the Marketing Department: {}", marketing::member_count());
// Usage crate Path Access
println!("Total Number of Employees: {}", marketing::total_employees());
// Usage as Avoiding Alias Conflicts
use company::engineering as eng;
println!("Department: {}", eng::team_name());
}
Output:
Engineering Department Front-End Team, 5 people
Engineering Department Backend Team, 8 people
Number of employees in the Marketing Department: 6
Total Number of Employees: 19
Department: Engineering Department
useIt's like creating a shortcut for a "house number" - so you don't have to type out the full address every timecompany::engineering::frontend::full_info().supermeans "go up one level" (parent module), andcratemeans "return to the building entrance" (crate root).asKeywords can be used to alias paths, resolving conflicts caused by duplicate names.
▶ Example 3: Dependency Management and Project Structure in Cargo.toml (Difficulty: ⭐⭐)
Output:
Today's Date: <date_utils::format_today()>
Email Verification: <string_utils::validate_email("test@example.com")>
Prime Number Check: <math_utils::is_prime(17)>
=== Tool Library Demo ===
Today: <date_utils::format_today()>
Is it the weekend?: <date_utils::is_weekend("Saturday")>
Email Verification test@example.com: <string_utils::validate_email("test@example.com")>
Email Verification invalid: <string_utils::validate_email("invalid")>
Purification 'hello@world!': <string_utils::sanitize("hello@world!")>
Fibonacci #10: <math_utils::fibonacci(10)>
17 Is it a prime number?: <math_utils::is_prime(17)>
4 Is it a prime number?: <math_utils::is_prime(4)>
=== End of Presentation ===
Usage `cargo test` Run Unit Tests
// ============================================
// Simulation Cargo Project Structure + Dependency Management
// Demo:lib.rs and main.rs Division of Labor、Using External Dependencies
// ============================================
// Note: This example demonstrates the code in lib.rs
// Actual Cargo.toml See the note below for the contents of the document.
// ============================================
// Cargo.toml Content (Simulation):
// ============================================
// [package]
// name = "my-toolkit"
// version = "0.1.0"
// edition = "2021"
//
// [dependencies]
// serde = { version = "1.0", features = ["derive"] }
// serde_json = "1.0"
// chrono = "0.4"
// regex = "1.10"
//
// [dev-dependencies]
// rand = "0.8"
//
// [profile.release]
// opt-level = 3
// ============================================
// Tools Module: Date Handling
pub mod date_utils {
pub fn format_today() -> String {
// Used in actual projects chrono::Local::now()
"2026-07-03".to_string()
}
pub fn is_weekend(day: &str) -> bool {
day.ends_with("Saturday") || day.ends_with("Sunday")
}
}
// Tools Module: String Processing
pub mod string_utils {
/// Verify the email address format (Simulating Regular Expression Matching)
pub fn validate_email(email: &str) -> bool {
// Simplified Verification: Use regex crate in practice
email.contains('@') && email.contains('.')
}
/// Remove non-alphanumeric characters (Simulation)
pub fn sanitize(input: &str) -> String {
input.chars()
.filter(|c| c.is_alphanumeric() || *c == ' ')
.collect()
}
}
// Tools Module: Mathematical Calculations
pub mod math_utils {
/// Calculate the nth term of the nth term of the Fibonacci sequence
pub fn fibonacci(n: u32) -> u64 {
match n {
0 => 0,
1 => 1,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
/// Determining Whether a Number Is Prime
pub fn is_prime(n: u32) -> bool {
if n < 2 {
return false;
}
let limit = (n as f64).sqrt() as u32;
for i in 2..=limit {
if n % i == 0 {
return false;
}
}
true
}
}
// Test Module (Using #[cfg(test)] Conditional Compilation)
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_email() {
assert!(string_utils::validate_email("user@example.com"));
assert!(!string_utils::validate_email("invalid"));
}
#[test]
fn test_fibonacci() {
assert_eq!(math_utils::fibonacci(0), 0);
assert_eq!(math_utils::fibonacci(1), 1);
assert_eq!(math_utils::fibonacci(10), 55);
}
#[test]
fn test_is_prime() {
assert!(math_utils::is_prime(17));
assert!(!math_utils::is_prime(1));
assert!(!math_utils::is_prime(4));
}
#[test]
fn test_sanitize() {
assert_eq!(string_utils::sanitize("hello@world!"), "hello world");
}
}
// ============================================
// main.rs The code in (Simulation):
// ============================================
// use my_toolkit::{
// date_utils,
// string_utils,
// math_utils,
// };
//
// fn main() {
// println!("Today's Date: {}", date_utils::format_today());
// println!("Email Verification: {}", string_utils::validate_email("test@example.com"));
// println!("Prime Number Check: {}", math_utils::is_prime(17));
// }
fn main() {
// Demonstration of Each Tool's Functions
println!("=== Tool Library Demo ===");
// Date Tools
println!("Today: {}", date_utils::format_today());
println!("Is it the weekend?: {}", date_utils::is_weekend("Saturday"));
// String Tools
println!("Email Verification test@example.com: {}", string_utils::validate_email("test@example.com"));
println!("Email Verification invalid: {}", string_utils::validate_email("invalid"));
println!("Purification 'hello@world!': {}", string_utils::sanitize("hello@world!"));
// Mathematical Tools
println!("Fibonacci #10: {}", math_utils::fibonacci(10));
println!("17 Is it a prime number?: {}", math_utils::is_prime(17));
println!("4 Is it a prime number?: {}", math_utils::is_prime(4));
println!("=== End of Presentation ===");
// Instructions for Running the Test (Use cargo test in actual projects)
println!("Usage `cargo test` Run Unit Tests");
}
Output:
=== Tool Library Demo ===
Today: 2026-07-03
Is it the weekend?: true
Email Verification test@example.com: true
Email Verification invalid: false
Purification 'hello@world!': hello world
Fibonacci #10: 55
17 Is it a prime number?: true
4 Is it a prime number?: false
=== End of Presentation ===
Usage `cargo test` Run Unit Tests
Standard structure for real projects:
lib.rscontains the library code (public API),main.rscontains the executable entry point (which uses the library).Cargo.tomlmanages dependencies,[dependencies]contains production dependencies, and[dev-dependencies]contains test/build tool dependencies.cargo testAutomatically discovers and runs functions marked with#[test].
▶ Example 4: Common Cargo Commands and Workspaces (Difficulty ⭐⭐⭐)
Output:
=== Task Manager (Simulation Workspace Project) ===
--- All Tasks ---
#<task.title> [<task.id>] <task.status> - <task.priority>
Done #<id1> after:
#<task.id> <task.title> - <status>
Urgent Task: #<task.title> <task.priority> (<task.id>)
=== End of Presentation ===
Project Structure: task-core (Library) + task-cli (CLI) + task-web (Web)
// ============================================
// Cargo Common Commands and workspace Multi-Package Management
// Simulation: One "Task Manager" workspace Project
// ============================================
// ============================================
// Top Floor Cargo.toml (workspace):
// ============================================
// [workspace]
// members = [
// "task-core", // Core Library
// "task-cli", // CLI Tools
// "task-web", // Web Interface
// ]
//
// [workspace.package]
// version = "1.0.0"
// edition = "2021"
// ============================================
// ============================================
// task-core/Cargo.toml:
// ============================================
// [package]
// name = "task-core"
// version.workspace = true
// edition.workspace = true
//
// [dependencies]
// serde = { version = "1.0", features = ["derive"] }
// chrono = "0.4"
// ============================================
// Simulation task-core Library code
pub mod task_core {
use std::collections::HashMap;
/// Task Priority
#[derive(Debug, Clone, PartialEq)]
pub enum Priority {
Low,
Medium,
High,
Urgent,
}
/// Task Status
#[derive(Debug, Clone, PartialEq)]
pub enum Status {
Todo,
InProgress,
Done,
Cancelled,
}
/// Core Task Structure
#[derive(Debug, Clone)]
pub struct Task {
pub id: u64,
pub title: String,
pub priority: Priority,
pub status: Status,
pub tags: Vec<String>,
}
impl Task {
pub fn new(id: u64, title: &str, priority: Priority) -> Task {
Task {
id,
title: title.to_string(),
priority,
status: Status::Todo,
tags: Vec::new(),
}
}
pub fn add_tag(&mut self, tag: &str) {
self.tags.push(tag.to_string());
}
pub fn is_completed(&self) -> bool {
self.status == Status::Done || self.status == Status::Cancelled
}
}
/// Task Manager
pub struct TaskManager {
tasks: HashMap<u64, Task>,
next_id: u64,
}
impl TaskManager {
pub fn new() -> TaskManager {
TaskManager {
tasks: HashMap::new(),
next_id: 1,
}
}
pub fn create_task(&mut self, title: &str, priority: Priority) -> u64 {
let id = self.next_id;
self.next_id += 1;
let task = Task::new(id, title, priority);
self.tasks.insert(id, task);
id
}
pub fn get_task(&self, id: u64) -> Option<&Task> {
self.tasks.get(&id)
}
pub fn complete_task(&mut self, id: u64) -> bool {
if let Some(task) = self.tasks.get_mut(&id) {
task.status = Status::Done;
true
} else {
false
}
}
pub fn list_tasks(&self) -> Vec<&Task> {
let mut tasks: Vec<&Task> = self.tasks.values().collect();
tasks.sort_by_key(|t| t.id);
tasks
}
}
}
// ============================================
// Cargo Command Reference (Demonstrated in the comments):
// ============================================
// Common Commands:
// cargo new project_name -- Create a New Project
// cargo build -- Compilation (debug)
// cargo build --release -- Compilation (release optimization)
// cargo run -- Compilation + Run
// cargo check -- Quickly Check for Compilation Errors (No binary files generated)
// cargo test -- Run Test
// cargo test test_name -- Run the specified test
// cargo bench -- Run Performance Benchmarks
// cargo doc --open -- Generate the document and open it
// cargo clippy -- Code lint Inspection
// cargo fmt -- Code Formatting
// cargo add crate_name -- Add Dependencies
// cargo update -- Update Dependencies
// cargo publish -- Post to crates.io
// cargo clean -- Clean up compilation output
//
// Workspace Commands:
// cargo build --workspace -- Compilation workspace All packages in
// cargo test -p task-core -- Test only the specified package
// cargo run -p task-cli -- Run the specified package
fn main() {
use task_core::{Priority, TaskManager};
println!("=== Task Manager (Simulation Workspace Project) ===");
let mut manager = TaskManager::new();
// Create a Task
let id1 = manager.create_task("Study Rust Smart Pointers", Priority::High);
let id2 = manager.create_task("Complete the module system exercises", Priority::Medium);
let id3 = manager.create_task("Restore the Production Environment Bug", Priority::Urgent);
// List all tasks
println!("\n--- All Tasks ---");
for task in manager.list_tasks() {
println!("#{} [{:?}] {} - {:?}", task.id, task.priority, task.title, task.status);
}
// Complete a task
manager.complete_task(id1);
println!("\nDone #{} after:", id1);
for task in manager.list_tasks() {
let status = if task.is_completed() { "Completed" } else { "In progress" };
println!("#{} {} - {}", task.id, task.title, status);
}
// Get a Single Task
if let Some(task) = manager.get_task(id3) {
println!("\nUrgent Task: #{} {} ({:?})", task.id, task.title, task.priority);
}
println!("\n=== End of Presentation ===");
println!("Project Structure: task-core (Library) + task-cli (CLI) + task-web (Web)");
println!("Usage `cargo test -p task-core` Testing the Core Library");
println!("Usage `cargo doc --open` Generate Document");
}
Output:
=== Task Manager (Simulation Workspace Project) ===
--- All Tasks ---
#1 [High] Study Rust Smart Pointers - Todo
#2 [Medium] Complete the module system exercises - Todo
#3 [Urgent] Restore the Production Environment Bug - Todo
Done #1 after:
#1 Study Rust Smart Pointers - Completed
#2 Complete the module system exercises - In progress
#3 Restore the Production Environment Bug - In progress
Urgent Task: #3 Restore the Production Environment Bug (Urgent)
=== End of Presentation ===
Project Structure: task-core (Library) + task-cli (CLI) + task-web (Web)
Usage `cargo test -p task-core` Testing the Core Library
Usage `cargo doc --open` Generate Document
Workspace is a powerful tool for managing multi-package projects:
task-coreprovides the core types and logic (libraries),task-cliprovides the command-line interface (executable),task-webprovides the Web API (another executable), andcargo build --workspacecompiles all packages at once.cargo test -p task-coretests only the core libraries.
▶ Example 5: Comprehensive Exercise—Modular Design Simulation (Difficulty ⭐⭐⭐)
Output:
=== math_utils Module ===
2 + 3 = <add(2, 3)>
4 * 5 = <multiply(4, 5)>
10 / 3 = <safe_divide(10, 3)>
10 / 0 = <safe_divide(10, 0)>
PI = <constants::PI>, E = <constants::E>
=== string_utils Module ===
capitalize: '<capitalize("rust")>'
truncate: '<truncate("Hello, World!", 8)>'
=== user Module ===
<alice.summary()>
Age: <alice.age()>
// ============================================
// Comprehensive Example: Module Visibility and API Design
// Simulating a Multi-File Project Structure (Actual projects should be broken down into separate files.)
// ============================================
mod math_utils {
pub fn add(a: i32, b: i32) -> i32 { a + b }
pub fn multiply(a: i32, b: i32) -> i32 { a * b }
fn internal_check(val: i32) -> bool { val >= 0 }
pub fn safe_divide(a: i32, b: i32) -> Option<i32> {
if b == 0 { return None; }
if !internal_check(a) || !internal_check(b) { return None; }
Some(a / b)
}
pub mod constants {
pub const PI: f64 = 3.14159265358979;
pub const E: f64 = 2.71828182845905;
pub const MAX_I32: i32 = i32::MAX;
}
}
mod string_utils {
pub fn capitalize(s: &str) -> String {
let mut chars = s.chars();
match chars.next() {
None => String::new(),
Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
}
}
pub fn truncate(s: &str, max_len: usize) -> String {
if s.len() <= max_len { s.to_string() }
else { format!("{}...", &s[..max_len.min(s.len())]) }
}
}
mod user {
pub struct User {
pub name: String,
age: u8,
email: String,
}
impl User {
pub fn new(name: &str, age: u8, email: &str) -> Self {
User { name: name.to_string(), age, email: email.to_string() }
}
pub fn age(&self) -> u8 { self.age }
pub fn summary(&self) -> String {
format!("{} ({} years old, {})", self.name, self.age, self.email)
}
}
}
fn main() {
use math_utils::{add, multiply, safe_divide, constants};
use string_utils::{capitalize, truncate};
use user::User;
println!("=== math_utils Module ===");
println!("2 + 3 = {}", add(2, 3));
println!("4 * 5 = {}", multiply(4, 5));
println!("10 / 3 = {:?}", safe_divide(10, 3));
println!("10 / 0 = {:?}", safe_divide(10, 0));
println!("PI = {:.5}, E = {:.5}", constants::PI, constants::E);
println!("\n=== string_utils Module ===");
println!("capitalize: '{}'", capitalize("rust"));
println!("truncate: '{}'", truncate("Hello, World!", 8));
println!("\n=== user Module ===");
let alice = User::new("Alice", 30, "alice@example.com");
println!("{}", alice.summary());
println!("Age: {}", alice.age());
}
Output:
=== math_utils Module ===
2 + 3 = 5
4 * 5 = 20
10 / 3 = Some(3)
10 / 0 = None
PI = 3.14159, E = 2.71828
=== string_utils Module ===
capitalize: 'Rust'
truncate: 'Hello, ...'
=== user Module ===
Alice (30 years old, alice@example.com)
Age: 30
Three Principles of Modular Design:
pubExpose only the necessary APIs (such asaddandsafe_divide), and keep internal details (such asinternal_check) private; Submodules (such asconstants) are exposed viapub mod; structure fields are individually annotated with visibility (privatepub name/age+age()getter).
❓ FAQ
mod and fn? Why not organize them using files?mod is a module definition, and fn is a function definition.pub(crate) and pub?pub(crate) is visible only to code within the same crate, while pub is visible to all external crates.use super::xxx and use crate::xxx be used?super is used to access the parent module (relative path), and crate is used to access content starting from the crate root (absolute path).^1.2.3 in Cargo.toml mean?^ stands for "compatibility update"—a version that allows >=1.2.3 and <2.0.0.lib.rs and main.rs coexist?📖 Summary
modKeyword definition module; can be nested (mod outer { mod inner { ... } }) or loaded from a file (mod xxx;)pubVisibility control: Private by default,pubpublic,pub(crate)visible only within the crate,pub(super)visible only to the parent moduleuseSimplifies calls by introducing paths; supports two types of relative/absolute paths:super(parent module) andcrate(root module)Cargo.tomlManage dependencies using semantic versioning (SemVer); separate[dependencies]from[dev-dependencies]cargo build/test/doc/benchare Cargo's core commands, whilecargo clippyandcargo fmtensure code quality- Workspace Multi-package management uses the
Cargo.tomlconfiguration at the top level;[workspace]lists all sub-packages
📝 Exercises
- Difficulty ⭐: Create a program containing two modules,
mathandgreeting. Themathmodule has a public functionadd(a: i32, b: i32) -> i32, and thegreetingmodule has a public functionsay_hello(name: &str) -> String. Call both of these functions inmain. - Difficulty ⭐⭐: Simulate a "library" module system. Create the
librarymodule, which includes thebookssubmodule (book management) and thememberssubmodule (member management).bookscontains theadd_bookandlist_booksfunctions, andmemberscontains theadd_memberandlist_membersfunctions. Usepub(super)andpub(crate)to control visibility appropriately. Themainmodule demonstrates how to add books and members. - Difficulty ⭐⭐⭐: Explore the Cargo workspace project structure. Create a workspace project locally that includes
core-lib(a library providing theaddandsubtractfunctions) andcli-app(an executable that performs calculations usingcore-liband prints the results). Configure the workspace settings forCargo.toml, compile it usingcargo build --workspace, and run it usingcargo run -p cli-app.