Modules and Visibility

mod

The mod keyword declares a new module as a child of the current module, establishing both a hierarchical namespace path and a privacy boundary for the items inside it.

The Two Forms of mod

Syntax Meaning Where rustc Looks for Code
mod name { ... } Defines an inline module directly inside the current file Inside { ... }
mod name; Declares an external file module and compiles it into the module tree name.rs or name/mod.rs (relative to parent module)
mod math_ops {
    pub fn clamp_u8(val: i32) -> u8 {
        val.clamp(0, 255) as u8
    }
}

fn main() {
    println!("Clamped 300 -> {}", math_ops::clamp_u8(300));
}
Clamped 300 -> 255

Combining Visibility with mod (mod vs pub mod)

Like any other item in Rust, a mod declaration is private to its parent module by default:

  • mod internal;: The parent module (and sibling modules in the same parent) can access internal::pub_item, but code outside the parent module cannot traverse through internal!
  • pub mod api;: Re-exports the module itself publicly so external callers can access parent::api::pub_item.
mod outer {
    mod secret_sub {           <-- Private `mod` (invisible outside `outer`!)
        pub fn helper() {}
    }
    pub mod public_sub {       <-- Public `pub mod` (visible outside `outer`!)
        pub fn endpoint() {}
    }
}
mod engine {
    // Private submodule: usable inside `engine`, hidden from `main`
    mod parser {
        pub fn parse_token(s: &str) -> &str {
            s.trim()
        }
    }

    // Public submodule: accessible from `main` as `engine::runner::run`
    pub mod runner {
        pub fn run(input: &str) {
            // Accesses sibling module `parser` via `super::parser`:
            let token = super::parser::parse_token(input);
            println!("Running token: '{token}'");
        }
    }
}

fn main() {
    engine::runner::run("  start_job  ");
    // `engine::parser::parse_token("x")` would fail with `E0603: module 'parser' is private`!
}
Running token: 'start_job'

Customizing File Paths with #[path = "..."]

If a platform-specific module file lives at a non-standard filesystem path (for example, src/os/unix_impl.rs vs src/os/windows_impl.rs), the #[path = "..."] attribute overrides where mod name; loads its source file from:

#[cfg(unix)]
#[path = "unix_sys.rs"]
mod sys;