Structs, Enums, and Modules
Explore struct and enum definitions for creating custom data structures. Learn how to organize code using modules.
Rust Modules: Organizing Your Code
What are Modules?
In Rust, modules are a fundamental building block for organizing code. They allow you to:
- Encapsulate functionality: Bundle related functions, structs, enums, and other items together.
- Control Visibility: Determine which items are accessible from outside the module and which are kept private.
- Improve Reusability: Make your code more modular and easier to reuse in different parts of your project or in other projects.
- Enhance Maintainability: Break down large codebases into smaller, more manageable units, making it easier to understand, modify, and debug.
Defining Modules
You define a module using the mod
keyword. Modules can be nested within each other.
Basic Module Definition
mod my_module {
// Module contents go here
}
Nested Modules
mod parent_module {
mod child_module {
// Contents of child_module
}
}
Modules in Separate Files
For larger projects, it's best practice to put each module in its own file. Rust automatically looks for a file with the same name as the module (e.g., my_module.rs
or my_module/mod.rs
) to find the module's contents.
Example structure:
src/
├── main.rs
└── my_module.rs // Or my_module/mod.rs
In src/main.rs
:
mod my_module; // Declare the module
fn main() {
my_module::hello();
}
In src/my_module.rs
:
pub fn hello() {
println!("Hello from my_module!");
}
Controlling Visibility: `pub`
By default, items defined within a module are private, meaning they can only be accessed from within the module itself. To make an item accessible from outside the module, you must use the pub
keyword.
Making Items Public
mod my_module {
pub fn public_function() {
println!("This is a public function.");
}
fn private_function() {
println!("This is a private function.");
}
}
fn main() {
my_module::public_function(); // Works
// my_module::private_function(); // Error: private_function is private
}
You can make other things public too, like structs, enums, and modules themselves.
mod my_module {
pub struct PublicStruct {
pub field1: i32, // public field
field2: i32, // private field
}
pub mod public_submodule {
pub fn another_public_function() {
println!("Hello from the public submodule!");
}
}
}
fn main() {
let my_struct = my_module::PublicStruct { field1: 10, field2: 20 };
println!("Public field: {}", my_struct.field1); // works
//println!("Private field: {}", my_struct.field2); // Doesn't work
my_module::public_submodule::another_public_function();
}
Using the `use` Keyword
The use
keyword brings items from a module into the current scope, allowing you to refer to them directly without specifying the full module path.
Importing Items
mod my_module {
pub fn greet(name: &str) {
println!("Hello, {}!", name);
}
}
use my_module::greet; // Import the greet function
fn main() {
greet("Alice"); // Use the function directly
}
Renaming Imports
You can rename imports using the as
keyword.
mod my_module {
pub fn greet(name: &str) {
println!("Hello, {}!", name);
}
}
use my_module::greet as say_hello; // Rename greet to say_hello
fn main() {
say_hello("Bob"); // Use the renamed function
}
Importing Multiple Items
You can import multiple items at once using curly braces.
mod my_module {
pub fn function1() { println!("Function 1"); }
pub fn function2() { println!("Function 2"); }
}
use my_module::{function1, function2};
fn main() {
function1();
function2();
}
Glob Imports (`use my_module::*`)
The wildcard *
can be used to import all public items from a module. However, this is often discouraged as it can make code less explicit and potentially lead to naming conflicts. Use with caution.
mod my_module {
pub fn function1() { println!("Function 1"); }
pub fn function2() { println!("Function 2"); }
}
use my_module::*; // Import everything public from my_module
fn main() {
function1();
function2();
}
Summary
Modules are essential for writing well-structured, maintainable Rust code. They allow you to organize your code into logical units, control visibility, and reuse code effectively. By mastering modules, you can build larger and more complex applications with confidence.