Modules and Visibility

Absolute and Relative Paths

To call a function, construct a type, or import an item located in a module, you specify its path in the module tree using either an absolute path (starting from the crate root or an external crate name) or a relative path (starting from the current module).

Comparing Absolute and Relative Paths

Path Kind Starting Segment Example Best Used When
Absolute (current crate) crate:: crate::billing::invoice::create() Referencing items in other subsystems of your crate; remains valid if the calling code is moved to a different module
Absolute (external crate) std:: or ::crate_name:: std::collections::HashMap Referencing items from the standard library or Cargo dependencies
Relative (child module) child_mod:: or self::child_mod:: invoice::create() Referencing a direct child module or an item already in scope
Relative (parent module) super:: super::shared_helper() Referencing an item in the immediate parent module (especially in mod tests)
Reaching `crate::audio::mixer::set_gain` from `crate::audio::effects::reverb`:

  crate
   └── mod audio
        ├── mod mixer
        │    └── pub fn set_gain()
        └── mod effects
             └── mod reverb
                  ├── Absolute path: `crate::audio::mixer::set_gain()`
                  └── Relative path: `super::super::mixer::set_gain()`

Absolute and Relative Paths in Action

mod audio {
    pub mod mixer {
        pub fn master_volume() -> u8 {
            85
        }
    }

    pub mod output {
        pub fn status_line() -> String {
            // 1. Absolute path from the crate root (`crate::...`):
            let vol_abs = crate::audio::mixer::master_volume();

            // 2. Relative path via parent module (`super::...`):
            let vol_rel = super::mixer::master_volume();

            assert_eq!(vol_abs, vol_rel);
            format!("Audio output active at volume {vol_abs}%")
        }
    }
}

fn main() {
    // Relative path from `main` (which is at the crate root) into child `audio`:
    println!("{}", audio::output::status_line());

    // Absolute path from `main` into `crate::audio`:
    println!("Master volume: {}%", crate::audio::mixer::master_volume());
}
Audio output active at volume 85%
Master volume: 85%

Choosing Between crate:: and Relative Paths

  1. Prefer crate:: when crossing subsystem boundaries: If crate::api::handlers calls into crate::db::users, writing use crate::db::users; makes it immediately clear where users lives in the project and continues to work if handlers is later split into handlers::v1.
  2. Prefer relative paths (child::... or super::...) for tightly coupled parent/child modules: When a parent module delegates to its own child module (child::run()) or a unit test submodule imports its parent (use super::*;), relative paths keep the parent and child portable as a unit if the entire folder is moved.

Disambiguating External Crate Names with a Leading ::

If your current module contains a child module with the same name as an external dependency crate (for example, mod serde;), prefixing the external crate name with a leading double colon (::serde::Serialize) forces the compiler to resolve serde as the external crate rather than the local serde module.