2.9 Modules and Crates: Code Organization

Modules encapsulate Rust source code, hiding internal implementation details. Crates are the fundamental units of code compilation and distribution in Rust.

2.9.1 Modules (mod)

Modules provide namespaces and control the visibility of items (functions, structs, etc.). Items within a module are private by default and must be explicitly marked pub (public) to be accessible from outside the module.

// Define a module named 'greetings'
mod greetings {
    // This function is private to the 'greetings' module
    fn default_greeting() -> String {
        // `to_string` is a method that converts a string literal (&str)
        // into an owned String.
        "Hello".to_string()
    }

    // This function is public and can be called from outside
    pub fn spanish() {
        println!("{} in Spanish is Hola!", default_greeting());
    }

    // Modules can be nested
    pub mod casual {
        pub fn english() {
            println!("Hey there!");
        }
    }
}

fn main() {
    // Call public functions using the module path `::`
    greetings::spanish();
    greetings::casual::english();
    // greetings::default_greeting(); // Error: private function
}

2.9.2 Splitting Modules Across Files

For larger projects, a module’s contents can be placed in a separate file instead of directly within its parent file. When you declare a module using mod my_module; in a file (e.g., main.rs or lib.rs), the compiler looks for the module’s code in one of two locations:

  1. In my_module.rs: A file named my_module.rs located in the same directory as the declaring file. This is the preferred convention since the Rust 2018 edition.
  2. In my_module/mod.rs: A file named mod.rs inside a subdirectory named my_module/. This is an older convention but still supported.

Cargo handles the process of finding and compiling these files automatically based on the mod declarations.

2.9.3 Crates

A crate is the smallest unit of compilation and distribution in Rust. There are two types:

  • Binary Crate: An executable program with a main function (like the my_project example earlier).
  • Library Crate: A collection of reusable functionality intended to be used by other crates (no main function). Compiled into a .rlib file by default (Rust’s static library format).

A Cargo project (package) can contain one library crate and/or multiple binary crates.

2.9.4 Comparison with C

  • Rust’s module system replaces C’s convention of using header (.h) and source (.c) files along with #include. Rust modules provide stronger encapsulation and avoid issues related to textual inclusion, multiple includes, and managing include guards.
  • Rust’s crates are analogous to libraries or executables in C, but Cargo integrates dependency management seamlessly, unlike typical C workflows that often require manual library linking and configuration.