Rust Book - Chapter 7.2

This chapter looks into why code organization is important, how this can be achieved using modules, as well as certain keywords that aid this process.

To get started, we look at these under a few heading to help us understand how modules work; as this is key to structuring our code.

The crate root

When compiling your code, the compiler first looks in the crate root file[1] for code to compile.

Declaring modules

You can declare new modules in the crate root file. The compiler looks in the following places for a modules code. Say you declare a module garden, with mod garden;:

  1. Inline, within curly brackets that replace the semicolon following mod garden.
  2. In the file src/garden.rs
  3. In the file src/garden/mod.rs

Declaring submodules

you can declare submodules in any other file than the crate root [1:1]. Example: Say you declare mod vegetables; in src/garden.rs; which is a module itself. The compiler will look for the submodule's code within the directory named for the parent module in these places:

  1. Inline, directly following mod vegetables, within curly brackets instead of the semicolon
  2. In the file src/garden/vegetables.rs
  3. In the file src/garden/vegetables/mod.rs

Paths to code in modules

Once a module is part of your crate, you can refer to code in that module from anywhere else in that same crate, as long as the privacy rules allow, using the path to code. E.g a Swallow [2] type in the food lunch module would be found at crate::food::lunch::Swallow.

Private vs public

Code within a module is private from its parent modules by default. To make a module public, declare it with pub mod instead of mod. Use pubbefore an item's declaration, to make items within a public module public.

The use keyword

Within a scope, use keyword creates shortcuts to items to reduce repetition of long paths. In any scope that can refer to crate::food::lunch::Swallow, you can create a shortcut with use crate::food::lunch::Swallow, and from then on, only write Swallow to make use of that type in the scope. (I too like swallow 😂. This is pidgin english [3] by the way).

@startfiles
/backyard/
/backyard/Cargo.lock
/backyard/Cargo.toml
/backyard/src/
/backyard/src/garden/
/backyard/src/garden/vegetable.rs
/backyard/src/garden.rs
/backyard/src/main.rs
@endfiles

The crate root file in this case is src/main.rs, containing:

Filename: src/main.rs

use crate::garden::vegetable::Asparagus;

pub mod garden;

fn main() {
    let plant = Asparagus {};
    println!("I'm growing {:?}!", plant
}

pub mod garden; tells the compiler to include the code it finds in src/garden.rs

Filename: src/garden.rs

pub mod vegetables; # code in src/garden/vegetables.rs is included too.

Filename: src/garden.vegetables.rs

#[derive(Debug)]
pub struct Asparagus {}

Why's the point of modules?

  1. Code organization within a crate for readability and easy reuse.
  2. control privacy of items, because code within a module is private by default.
#content of src/lib.rs for a restaurant crate
mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}

        fn seat_at_table() {}
    }

    mod serving {
        fn take_order() {}

        fn serve_order() {}

        fn take_payment() {}
    }
}

The reason src/main.rs and src/lib.rs are called crate roots is that the contents of either of these twor files form a module named crate.


  1. The crate root file is the first file that the compiler looks for when it compiles your code. This is either the src/lib.rs for library crate or src/main.rs for binary crate. ↩ī¸Ž ↩ī¸Ž

  2. Food that's typically swallowed, instead of chewed, and is used as an accompaniment to soups in Nigeria 😄. E.g Eba ↩ī¸Ž

  3. Nigerian Pidgin is a form of English mixed with the Local languages of the people. Normally more interesting than the original 😎. Nigerian Pdigin ↩ī¸Ž