Private Items
In Rust, every item in a module is private by default unless preceded by a pub visibility modifier. However, Rust's privacy rule has an important asymmetric property: parent modules cannot see private items inside their child modules, but child modules (and all deeper descendants) can see every private item in their ancestor modules.
The Asymmetric Parent-Child Privacy Rule
Why can child modules access private items of their parent modules? Because a child module is an implementation detail written by the author of the parent module—often used to group helper code or unit tests (mod tests)—so giving child modules automatic access to their ancestors' private items avoids forcing the parent module to widen visibility.
Who Can See Private Items?
mod parent {
fn parent_secret() {} <-- Private to `parent`
struct Vault { pin: u16 } <-- `Vault` and `pin` are private to `parent`
mod child {
// Child CAN access `super::parent_secret()` and `Vault.pin`!
fn child_secret() {} <-- Private to `child`
}
// `parent` CANNOT access `child::child_secret()` unless marked `pub(super)` or `pub`!
}
| Item Defined In | Visibility | Accessible in Same Module? | Accessible in Child / Descendant Modules? | Accessible in Parent / Sibling Modules? |
|---|---|---|---|---|
mod m |
Private (default) | Yes | Yes | No |
mod m |
pub(self) |
Yes | Yes (identical to private) | No |
Child Modules Accessing Private Parent Items (including #[cfg(test)] mod tests)
This rule is the reason unit tests in a child mod tests block can test private functions and inspect private struct fields of the parent module via use super::*;:
mod crypto {
// Private constant and private struct field in `mod crypto`
const SALT: u64 = 0x517C_C1B7_2722_0A95;
pub struct Hasher {
state: u64, // Private field
}
// Private helper function in `mod crypto`
fn mix(value: u64) -> u64 {
value.wrapping_mul(SALT)
}
pub mod verifier {
use super::{Hasher, mix};
// Child module `verifier` can construct `Hasher` (accessing private `state`)
// and call private function `mix()` from its parent `crypto`:
pub fn create_and_verify(input: u64) -> u64 {
let h = Hasher { state: mix(input) };
h.state
}
}
}
fn main() {
let digest = crypto::verifier::create_and_verify(42);
println!("Digest: 0x{digest:016X}");
}
Digest: 0x5B2E9BC3A59AB1F2
Exception: Enum Variants and Trait Items Are Public When Their Container Is pub
While struct fields and module items are private by default, two constructs inherit the visibility of their enclosing declaration:
pub enumvariants: If anenumis markedpub, all of its variants and their fields are automaticallypub. (An enum whose variants were hidden could not be matched or constructed by callers.)pub traitmethods and associated types: If atraitis markedpub, all of its methods, associated types, and associated constants are automaticallypub(and you cannot writepub fninside atraitblock).
mod status {
// Marking the enum `pub` automatically makes `Ready` and `Busy(u32)` public:
#[derive(Debug)]
pub enum WorkerState {
Ready,
Busy(u32),
}
}
fn main() {
let state = status::WorkerState::Busy(4);
println!("Worker state: {state:?}");
}
Worker state: Busy(4)