Step 2 of 7
Paths: crate, super and self
A path names an item. There are two kinds:
- Absolute paths start at the crate root with
crate::, like a full address:crate::restaurant::kitchen::cook. - Relative paths start from the current module: a child's name (
kitchen::cook),super::(the parent module) orself::(this module; rarely needed).
The crate root is the top of the module tree: the file main.rs (or lib.rs) itself. Everything you write at the top level, like fn main, lives there. The module tree of the next example:
crate (main.rs, the crate root)
├── fn log
├── fn main
└── mod restaurant
├── fn open
├── fn ring_bell
└── mod kitchen
├── fn cook
└── fn prep
fn log(msg: &str) {
println!("[log] {msg}");
}
mod restaurant {
pub fn open() {
crate::log("opening"); // absolute: from the crate root
kitchen::cook("soup"); // relative: kitchen is a child of restaurant
}
fn ring_bell() {
println!("ding!");
}
pub mod kitchen {
pub fn cook(dish: &str) {
prep(dish); // same module: just the name
println!("{dish} is ready");
super::ring_bell(); // the parent module, restaurant
}
fn prep(dish: &str) {
println!("chopping for {dish}");
}
}
}
fn main() {
restaurant::open();
restaurant::kitchen::cook("salad");
}
[log] opening
chopping for soup
soup is ready
ding!
chopping for salad
salad is ready
ding!
super::ring_bell():kitchenlives insiderestaurant, sosuperisrestaurant. A child may use its parent's private items, soring_belldoesn't needpub.crate::log(...): from anywhere,crate::starts at the root. The root's private items are visible everywhere in the crate, because every module is inside the root.mainis in the root, sorestaurant::...frommainis relative and absolute at the same time.
Which kind should you write? Absolute crate:: paths keep working when you move the code that uses them; relative super:: paths keep working when you move a module together with its parent. Many teams prefer crate:: in general for clarity, and super:: for close relatives, most famously use super::*; in test modules (the testing module).
Common mistake: names from outside the module
A module does not see the names of the scope around it, unlike a block inside a function:
fn log(msg: &str) {
println!("[log] {msg}");
}
mod restaurant {
pub fn open() {
log("opening");
}
}
fn main() {
restaurant::open();
}
error[E0425]: cannot find function `log` in this scope
The compiler suggests consider importing this function: use crate::log;. Either write the path (crate::log("opening") or super::log(...)) or bring the name in with use, the next step.
Your task
The starter doesn't compile: inside teller::withdraw, the calls to fee and audit can't find those functions. Give each call the right path: fee lives in the parent module bank (use super::), and audit lives in the crate root (use crate::). The program should print:
audit: withdrawal
balance: 68
Challenge 2
Fill in the two path prefixes: heal (in game::player) needs max_hp from its parent module game, and price_with_bonus (in shop) needs bonus from the crate root. The program prints:
80
100
15
Challenge 3
Build this module tree. shout is given at the root.
crate
├── fn shout(s: &str) -> String (given: uppercases and adds "!")
└── mod notify
├── pub fn alert(msg: &str) -> String
│ "[ALERT] " followed by shout(msg)
└── pub mod email
└── pub fn subject(msg: &str) -> String
"Subject: " followed by alert(msg)
So notify::alert("disk full") is "[ALERT] DISK FULL!" and notify::email::subject("disk full") is "Subject: [ALERT] DISK FULL!". Reach shout and alert with paths (crate:: or super::); don't copy their code.
Previous: Modules and privacy Next: use: shortcuts for long paths