In Rust, to locate an item in a module tree, we use a path, similar to how we navigate a filesystem. To invoke a function, we need to know its path. A path can take two forms:
- Absolute Path: This is the full path starting from a crate root. For code from an external crate, the absolute path begins with the crate name. For code from the current crate, it starts with the literal `crate`.
- Relative Path: This starts from the current module and uses `self`, `super`, or an identifier in the current module.
Both absolute and relative paths are followed by one or more identifiers separated by double colons (`::`).
Let's consider we want to call the `add_to_waitlist` function. We can show two ways to call the `add_to_waitlist` function from a new function `eat_at_restaurant` defined in the crate root. These paths are correct, but there’s another problem remaining that will prevent this example from compiling as-is.
The `eat_at_restaurant` function is part of our library crate’s public API, so we mark it with the `pub` keyword.
Rust
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
}
The first time we call the `add_to_waitlist` function in `eat_at_restaurant`, we use an absolute path. The `add_to_waitlist` function is defined in the same crate as `eat_at_restaurant`, which means we can use the `crate` keyword to start an absolute path.
The second time we call `add_to_waitlist` in `eat_at_restaurant`, we use a relative path. The path starts with `front_of_house`, the name of the module defined at the same level of the module tree as `eat_at_restaurant`.
Choosing whether to use a relative or absolute path is a decision you’ll make based on your project. It depends on whether you’re more likely to move item definition code separately from or together with the code that uses the item.
However, if we try to compile, we get an error. The error messages say that module `hosting` is private. In other words, we have the correct paths for the `hosting` module and the `add_to_waitlist` function, but Rust won’t let us use them because it doesn’t have access to the private sections.
In Rust, all items (functions, methods, structs, enums, modules, and constants) are private to parent modules by default. If you want to make an item like a function or struct private, you put it in a module.
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. This is because child modules wrap and hide their implementation details, but the child modules can see the context in which they’re defined.
Rust chose to have the module system function this way so that hiding inner implementation details is the default. That way, you know which parts of the inner code you can change without breaking outer code. However, Rust does give you the option to expose inner parts of child modules’ code to outer ancestor modules by using the `pub` keyword to make an item public.