Modules

Crates can contain modules.

Declaring modules: In the crate root file (main.rs or lib.rs), you can declare new modules; say, you declare a “garden” module with mod garden; (or pub mod garden; for public); The compiler will look for the module’s code in these places:

  • Inline, within curly brackets that replace the semicolon following mod garden
  • In the file src/garden.rs
  • In the file src/garden/mod.rs (older style)

In any file other than the crate root, you can declare submodules. For example, you might declare mod vegetables; in src/garden.rs. The compiler will look for the submodule’s code within the directory named for the parent module in these places:

  • Inline, directly following mod vegetables, within curly brackets instead of the semicolon
  • In the file src/garden/vegetables.rs
  • In the file src/garden/vegetables/mod.rs (older style)

In Rust, all items (functions, methods, structs, enums, modules, and constants) are private to parent modules by default. Items can access other items in the same module, even when private.

Items in a parent module can’t use the private items inside child modules, but items in child modules can use the items in their ancestor modules.

visibility-rules-rust-by-example-badge

A clear explanation of Rust’s module system

Use keyword

Create a shortcut to a path with the use keyword once, and then use the shorter name everywhere else in the scope.

use-rust-by-example-badge

#![allow(unused_imports, dead_code)]

// For code from an external crate, the absolute path begins with the crate name
// Here, the standard `std` library
use std::collections::HashMap;
// With the following, `File` without prefix is available in the scope
use std::fs::File;
// Glob - all public objects in `collections` are now in scope
use std::collections::*;
// Combine multiple `use` lines together with { }
use std::{cmp::Ordering, fmt};
// The following is equivalent to `use std::io; use std::io::Write;`
use std::io::{self, Write};

mod utils {
    pub fn insert_use() {}
}
// Absolute path - for code from the current crate, it starts with the literal crate.
use crate::utils::insert_use;

mod a {
    pub mod b {}
}
// A relative path starts from the current module and uses `self`, `super`,
// or an identifier in the current module.
use self::a::b;

mod c {
    // We can construct relative paths that begin in the parent module,
    // rather than the current module or the crate root, by using `super`
    // at the start of the path.
    use super::a;
}

use std::fmt::Result;
use std::io::Result as IoResult; // Alias

mod front_of_house {
    pub mod hosting {}
}
// Reexporting - `pub use` re-exports the `hosting` module from the root module,
// thus external code can use the path `<crate>::hosting::add_to_waitlist()`
// instead of `crate::front_of_house::hosting::add_to_waitlist()`.
pub use crate::front_of_house::hosting;

fn main() {}

Idiomatic - bringing the function’s parent module into scope, not the function itself:

use front_of_house::hosting;

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

fn main() {
    eat_at_restaurant();
}

On the other hand, when bringing in structs, enums, and other items with use, it’s idiomatic to specify the full path.

use std::collections::HashMap;

fn main() {
    let mut _map: HashMap<u32, String> = HashMap::new();
}