C.W.K.
Stream
Lesson 01 of 06 · published

Modules & Visibility

~11 min · tooling, modules, visibility, use

Level 0Rust Curious
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

As a program grows past one file, you need structure: a way to group related code and control what's visible where. Rust's answer is the module systemmod, visibility, and use.

mod: grouping code

mod name { ... } declares a module — a named namespace for related items. Modules can nest, and they map naturally onto files: mod foo; tells Rust to load foo.rs (or foo/mod.rs) as that module. You build a tree of modules rooted at your crate.

Visibility: private by default

Everything in Rust is private to its module by default — a function, struct, or field is only visible within the module that defines it (and its children). You opt into visibility with pub: pub fn, pub struct, pub on individual fields. This is the opposite of many languages' default-public, and it's deliberate: you expose your API surface explicitly, so nothing leaks by accident.

Private by default; pub is opt-in. Your module's internals stay hidden unless you mark them pub. This makes the public API a deliberate, visible choice — refactor internals freely, knowing only the pub items are part of your contract with callers.

use: bringing paths into scope

use crate::foo::bar brings bar into scope so you can call it unqualified. Paths start from crate (your crate root), self (current module), or super (parent). use is just an import — it doesn't move code, only shortens how you refer to it. Idiomatic Rust groups use statements at the top of each file.

Code

A module, pub visibility, and a use import·rust
mod geometry {
    pub struct Circle { pub radius: f64 } // pub struct + pub field

    impl Circle {
        pub fn area(&self) -> f64 {        // pub method
            std::f64::consts::PI * self.radius * self.radius
        }
    }

    fn helper() {}  // private: only callable inside `geometry`
}

use geometry::Circle; // bring the path into scope

fn main() {
    let c = Circle { radius: 2.0 };
    println!("{:.2}", c.area());
}

External links

Exercise

Create a module with one pub function and one private helper it calls internally. From main, call the public function (works) and try to call the private helper (fails to compile). Then use the public function to call it without the module prefix. What does keeping the helper private buy you?
Hint
A private helper is free to change or delete — it's not part of your module's contract. Only the pub items are. Privacy lets you refactor internals without fear of breaking callers.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.