Modules

Rust by example - 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.

book-rust-by-example-visibility-rules

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.

book-rust-by-example-use


// With the following, `File` without prefix is available in the scope
// For code from an external crate, the absolute path begins with the
// crate name - here, the standard `std` library
use std::collections::HashMap;
// Glob - all public objects in `collections` are now in scope
// Use sparingly
use std::collections::*;
// Use `as` to define aliases, for example in case of name conflict
use std::fmt::Result;
use std::fs::File;
use std::io::Result as IoResult;
// The following is equivalent to `use std::io; use std::io::Write;`
use std::io::{self, Write};
// You can combine multiple `use` lines together with { } as well
use std::{cmp::Ordering, fmt};

mod a {
    pub mod b {
        pub fn fn_in_b() {
            println!("in b!");
        }
    }
    pub struct A;
}
// For internal code, a relative path starts from the current module and uses
// `self`, or an identifier in the current module.
use self::a::b;
// b is now in scope

// Try the simpler version:
// use a::b;

fn do_something() {
    b::fn_in_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;
    // a is now in scope

    pub fn do_something_else() {
        let _a = a::A;
        println!("do_something_else");
    }
}

mod d {
    pub fn let_try_this() {}
}
// Absolute paths start with the literal `crate`.
// You can try:
// use crate::d;

mod e {
    pub mod f {
        pub fn try_that() {
            println!("try_that");
        }
    }
}
// `pub use` re-exports the `f` module from the
// root module, thus external code can use the path
// `<crate_name>::f::try_that()` instead of
// `<crate_name>::e::f::try_that()`.
pub use e::f;

fn main() {
    do_something();
    c::do_something_else();
    // You can of course access the item made public by `pub use` from your
    // module
    f::try_that();
}

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


// We bring the hosting module in scope...
use front_of_house::hosting;

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {
            println!("add_to_waitlist");
        }
    }
}

fn eat_at_restaurant() {
    // ...then we access the function within
    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.

// Bring `HashMap` in scope
use std::collections::HashMap;

fn main() {
    // We now refer to `HaspMap` without using its path
    let mut mymap: HashMap<u32, String> = HashMap::new();

    // Let's add something to it then print...
    mymap.entry(42).or_insert("my favorite number".into());
    println!("{:?}", mymap);
}