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 sub-modules. 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

// The `use` keyword brings items into scope.
// With the following, `File` can be used without prefix in the scope.
// For code from an external crate, the absolute path begins with the crate name.
// Here, the standard `std` library is an external crate.
use std::collections::HashMap;
use std::fmt::Result;
use std::fs::File;

// 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::io::Result as IoResult;

// You can combine multiple `use` lines together with { } as well
use std::{cmp::Ordering, fmt};
// The following is equivalent to `use std::io; use std::io::Write;`
use std::io::{self, Write};

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;

/// This module represents the front of the house in a restaurant.
mod front_of_house {
    /// This module handles hosting duties.
    pub mod hosting {
        /// Adds a customer to the waitlist.
        pub fn add_to_waitlist() {
            println!("add_to_waitlist");
        }
    }
}

fn eat_at_restaurant() {
    // We can now access the function within the hosting module
    // without specifying the whole path.
    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.

// This allows us to use `HashMap` directly without having to
// specify its full path.
use std::collections::HashMap;

fn main() {
    // We now refer to `HashMap` 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);
}

Related Topics

  • Package Layout.

References