#13 Modules and crates
mod, use, pub, crate
What is a module?
Modules let you organize your code into logical groups. They control the visibility (public vs private) of items like functions, structs, and constants. Every Rust file is implicitly a module.
A crate is the top-level unit of compilation. A crate can be a binary (main.rs) or a library (lib.rs). Modules live inside crates.
The mod keyword
You define a module with the mod keyword. Modules can be nested:
mod greetings {
pub fn hello() {
println!("Hello from greetings module!");
}
fn secret() {
println!("This is private");
}
}
fn main() {
greetings::hello(); // OK: hello is pub
// greetings::secret(); // ERROR: secret is private
}Items inside a module are private by default. Only the module itself and its children can access private items.
Visibility (pub)
The pub keyword makes an item accessible from outside its module. You can apply it to functions, structs, fields, enums, and more:
mod geometry {
pub struct Circle {
pub radius: f64, // public field
color: String, // private field
}
impl Circle {
pub fn new(radius: f64) -> Circle {
Circle {
radius,
color: String::from("red"),
}
}
pub fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
}
}
fn main() {
let c = geometry::Circle::new(5.0);
println!("Area: {:.2}", c.area());
println!("Radius: {}", c.radius); // OK: pub field
// println!("{}", c.color); // ERROR: private field
}The use keyword
Writing the full path every time is verbose. The use keyword brings items into scope:
mod math {
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn multiply(a: i32, b: i32) -> i32 {
a * b
}
}
// Bring specific items into scope
use math::add;
use math::multiply;
// Or bring multiple items at once
// use math::{add, multiply};
fn main() {
println!("{}", add(2, 3));
println!("{}", multiply(4, 5));
}You can also rename imports with as:
use std::collections::HashMap as Map;
let mut m = Map::new();
m.insert("key", "value");Splitting into files
For larger projects, you put each module in its own file. The file structure mirrors the module hierarchy:
src/
main.rs // crate root
database.rs // mod database
network/
mod.rs // mod network
client.rs // mod network::client
server.rs // mod network::serverIn main.rs, you declare the modules:
mod database;
mod network;
use database::connect;
use network::client::fetch;
fn main() {
connect("myapp.db");
fetch("https://example.com");
}pub fn connect(db_name: &str) {
println!("Connected to database: {}", db_name);
}pub mod client;
pub mod server;pub fn fetch(url: &str) {
println!("Fetching: {}", url);
}Summary
mod name { } // Define an inline module
pub fn/struct/... // Make an item public
use path::item; // Bring item into scope
use path::{a, b}; // Bring multiple items
use path::item as x; // Rename an import
mod name; // Load module from file
// File-based modules:
// src/foo.rs -> mod foo
// src/foo/mod.rs -> mod foo (with submodules)
// src/foo/bar.rs -> mod foo::barYour turn
Try building and running the modules demo with cargo build and cargo run: