Labs ICT
Pro Login

Modules and Crates

Organizing code into packages.

Modules and Crates in Rust

Modules help you organize code into logical units. They control visibility and prevent naming conflicts. A crate is a package of Rust code, and modules are how you structure it.

Think of modules as namespaces that group related functionality together.

mod math {
    pub fn add(a: i32, b: i32) -> i32 {
        a + b
    }

    pub fn multiply(a: i32, b: i32) -> i32 {
        a * b
    }
}

fn main() {
    println!("2 + 3 = {}", math::add(2, 3));
    println!("2 * 3 = {}", math::multiply(2, 3));
}
Try it Yourself ->

Visibility with pub

By default, everything in a module is private. Use pub to make items visible to outside code. You can also use pub(crate) to limit visibility to within the crate.

mod restaurant {
    pub struct Breakfast {
        pub toast: String,
        seasonal_fruit: String,
    }

    impl Breakfast {
        pub fn summer(toast: &str) -> Breakfast {
            Breakfast {
                toast: String::from(toast),
                seasonal_fruit: String::from("peaches"),
            }
        }
    }
}

fn main() {
    let mut meal = restaurant::Breakfast::summer("wheat");
    meal.toast = String::from("rye".to_string());
    println!("I'd like {} toast please", meal.toast);
    // Can't access meal.seasonal_fruit because it's private
}
Try it Yourself ->

Using use for Imports

The use keyword brings items into scope, so you don't have to write the full path every time. It's like importing in other languages.

mod shapes {
    pub fn circle_area(radius: f64) -> f64 {
        std::f64::consts::PI * radius * radius
    }

    pub fn rectangle_area(width: f64, height: f64) -> f64 {
        width * height
    }
}

use shapes::{circle_area, rectangle_area};

fn main() {
    println!("Circle area: {:.2}", circle_area(5.0));
    println!("Rectangle area: {:.2}", rectangle_area(4.0, 6.0));
}
Try it Yourself ->

Crate Root and Module Tree

Every crate has a root file (main.rs or lib.rs) that defines the top-level module. The module tree is like a directory structure for your code.

// In main.rs, you can define modules inline:
mod config {
    pub const MAX_SIZE: usize = 100;
    pub const VERSION: &str = "1.0";
}

mod database {
    pub fn connect(url: &str) -> bool {
        println!("Connecting to {}", url);
        true
    }
}

use config::{MAX_SIZE, VERSION};

fn main() {
    println!("Version: {}", VERSION);
    println!("Max size: {}", MAX_SIZE);
    database::connect("localhost:5432");
}
Try it Yourself ->

Cargo.toml Dependencies

Cargo.toml is where you declare dependencies. The crates.io ecosystem has thousands of packages ready to use.

// Example Cargo.toml section:
// [dependencies]
// serde = { version = "1.0", features = ["derive"] }
// tokio = { version = "1", features = ["full"] }
// reqwest = "0.11"

fn main() {
    println!("Dependencies are declared in Cargo.toml");
    println!("Use 'cargo add' to add new dependencies");
}
Try it Yourself ->

File Organization

Rust has two ways to organize modules in files. You can use mod.rs files or the folder naming convention. Both approaches are valid and widely used.

The folder naming convention (src/module_name.rs) is generally preferred for new projects because it's easier to navigate.

Crates.io Ecosystem

Crates.io is Rust's package registry. It has packages for everything from web frameworks to cryptography to game development. Before writing your own code, check if there's already a crate for what you need.

Popular crates like serde, tokio, and reqwest are well-maintained and widely used in production.