Rust Modules and Code Organization
As your Rust program grows, putting all code in one file becomes hard to manage. Modules let you split code into logical groups, control what is visible to other parts of the program, and keep each file focused on one responsibility.
What Is a Module?
A module is a named container for functions, structs, enums, constants, and other modules. Think of it as a folder within your code that groups related items together.
The Office Building Diagram
Crate (whole program)
│
├── mod accounting { ... } ← Accounting department
├── mod hr { ... } ← HR department
└── mod engineering {
mod frontend { ... } ← Sub-team inside engineering
mod backend { ... } ← Sub-team inside engineering
}
Defining a Module
mod greetings {
pub fn hello() {
println!("Hello!");
}
pub fn goodbye() {
println!("Goodbye!");
}
}
fn main() {
greetings::hello();
greetings::goodbye();
}
Output:
Hello! Goodbye!
The mod keyword defines a module. The double colon :: separates the module name from the item you are accessing.
Visibility with pub
By default, everything inside a module is private — only code within the same module can use it. Add the pub keyword to make an item visible to the outside world.
mod kitchen {
pub fn serve_food() {
println!("Food served!");
prepare_plate(); ← Calling a private function from inside the module is fine
}
fn prepare_plate() { ← Private: only usable inside kitchen
println!("Plate ready.");
}
}
fn main() {
kitchen::serve_food(); ← Works: serve_food is pub
kitchen::prepare_plate(); ← Compiler error: prepare_plate is private
}
Nested Modules
Modules can contain other modules. Access nested items by chaining names with :::
mod school {
pub mod math {
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
}
}
fn main() {
let result = school::math::add(3, 4);
println!("{}", result); ← 7
}
The use Keyword
Typing long module paths every time gets repetitive. Use use to bring a path into scope:
use school::math::add;
fn main() {
let result = add(3, 4); ← No need to type school::math::add
println!("{}", result);
}
You can also import multiple items from the same module:
use std::collections::{HashMap, HashSet};
Modules in Separate Files
For larger programs, move each module into its own file. If you declare mod greetings; in main.rs, Rust looks for either:
src/greetings.rs— a single file for the modulesrc/greetings/mod.rs— a folder with a mod.rs file
Example File Structure
src/ ├── main.rs ├── greetings.rs ← Content of mod greetings └── math.rs ← Content of mod math
In main.rs:
mod greetings;
mod math;
fn main() {
greetings::hello();
let sum = math::add(1, 2);
}
In src/greetings.rs:
pub fn hello() {
println!("Hello from greetings module!");
}
Paths: Absolute and Relative
crate::school::math::add(1, 2) ← Absolute path (start from crate root) school::math::add(1, 2) ← Relative path (start from current module) super::helper() ← Go up one level to parent module
pub Structs and Enums
Making a struct public does not automatically make its fields public. You must mark each field you want visible with pub individually:
mod shapes {
pub struct Rectangle {
pub width: f64, ← Public field
pub height: f64, ← Public field
area_cache: f64, ← Private field (hidden from outside)
}
}
For enums, making the enum pub makes all its variants public automatically.
Quick Reference
mod name { } ← Define a module
pub fn name() { } ← Make function visible outside module
use module::item; ← Bring item into current scope
crate::module::item ← Absolute path from crate root
super::item ← Access parent module
mod name; ← Load module from a separate file
