Module Trees
Every Rust crate has a single hierarchical module tree rooted at an implicit module named crate, which corresponds to the crate root file (src/lib.rs for a library crate or src/main.rs for a binary crate).
How the Compiler Builds the Module Tree
Unlike Python or Go—where the compiler or runtime automatically discovers .py or .go files in a directory—Rust only compiles files that are explicitly attached to the module tree via a mod name; declaration, starting from src/lib.rs or src/main.rs.
Filesystem Layout vs. Logical Module Tree (`crate`):
Filesystem (`src/`): Logical Module Tree:
src/
├── main.rs (contains `mod net; crate
│ mod config;`) ├── net
├── config.rs │ ├── tcp
└── net/ │ └── tls
├── mod.rs (or `src/net.rs`) └── config
├── tcp.rs
└── tls.rs
Addressing Items in the Module Tree
Just as directories and files in a filesystem are addressed by / paths, modules and items in the module tree are addressed using :: paths:
| Module Tree Concept | Filesystem Analogy | Rust Syntax |
|---|---|---|
| Crate root | / (root directory) |
crate |
| Current module | . (current directory) |
self |
| Parent module | .. (parent directory) |
super |
| Path separator | / |
:: |
| Attaching a child module | Creating a subdirectory entry | mod child; |
Inspecting a Complete Multi-Level Module Tree
// Crate root (`crate`)
mod config {
pub const DEFAULT_TIMEOUT_MS: u64 = 1500;
}
mod net {
pub mod tcp {
pub fn connect(addr: &str) -> String {
// Access a sibling subtree (`crate::config`) from `crate::net::tcp`:
let timeout = crate::config::DEFAULT_TIMEOUT_MS;
format!("TCP connected to {addr} (timeout = {timeout}ms)")
}
}
pub mod tls {
pub fn handshake(addr: &str) -> String {
// Access a sibling module (`super::tcp`) inside `crate::net`:
let base = super::tcp::connect(addr);
format!("{base} + TLS 1.3 handshake complete")
}
}
}
fn main() {
let status = crate::net::tls::handshake("10.0.0.1:443");
println!("{status}");
}
TCP connected to 10.0.0.1:443 (timeout = 1500ms)
TCP connected to 10.0.0.1:443 (timeout = 1500ms) + TLS 1.3 handshake complete
Wait—notice how net::tls::handshake calls super::tcp::connect(addr) once and formats the returned string cleanly:
TCP connected to 10.0.0.1:443 (timeout = 1500ms) + TLS 1.3 handshake complete
Visibility Along a Module Tree Path
For code in module A to refer to an item via a path crate::m1::m2::Item, every segment of the path not already an ancestor of A (m1, m2, and Item) must be visible to A. Even if Item is marked pub, if its enclosing module m2 is private (and not an ancestor of A), A cannot reach m2::Item unless m1 re-exports it with pub use self::m2::Item;.