Modules and Visibility
pub
In Rust, every item (fn, struct, enum, mod, const, type, trait) and struct field is private to its defining module by default. Adding the pub keyword makes the item public so that code outside the module can access it (provided the containing module path is also accessible).
How pub Behaves Across Different Item Kinds
A critical distinction in Rust is how pub behaves on a struct versus an enum or trait:
| Construct | Effect of pub on the Item Itself |
Are Inner Fields / Variants / Methods Automatically pub? |
|---|---|---|
pub fn / pub const / pub type |
Callable or usable outside the module | N/A |
pub mod name |
Allows external code to traverse into name::... |
No (items inside name remain private unless marked pub!) |
pub struct Name |
Makes the struct type Name public |
No! Struct fields and methods remain private by default unless individually marked pub! |
pub enum Name |
Makes the enum type Name public |
Yes! All enum variants and variant fields become public automatically! |
pub trait Name |
Makes the trait Name public |
Yes! All trait methods are automatically public whenever the trait is in scope! |
Struct vs Enum Visibility Rule:
pub struct Account {
pub username: String, <-- Public field (explicit `pub` required)
password_hash: String, <-- PRIVATE field (default inside `pub struct`!)
}
pub enum Status {
Active(u32), <-- PUBLIC variant & field (automatic inside `pub enum`!)
Suspended { reason: String },
}
mod auth {
pub struct User {
pub username: String, // Public: readable and writable outside `auth`
role_id: u8, // Private: hidden from code outside `auth`
}
pub enum Role {
Member,
Admin { level: u8 }, // Automatically public because `Role` is `pub enum`
}
impl User {
pub fn new(username: &str, role: Role) -> Self {
let role_id = match role {
Role::Member => 1,
Role::Admin { level } => 100 + level,
};
Self {
username: String::from(username),
role_id,
}
}
pub fn is_admin(&self) -> bool {
self.role_id >= 100
}
}
}
fn main() {
let admin = auth::User::new("ferris", auth::Role::Admin { level: 5 });
// `admin.username` and `admin.is_admin()` are public:
println!("User '{}' is admin: {}", admin.username, admin.is_admin());
// Accessing `admin.role_id` directly here would fail with `E0616: field 'role_id' is private`!
}
User 'ferris' is admin: true
Why Private Struct Fields Prevent Direct Literal Construction (E0451)
If a pub struct has even one private field, code outside its module cannot construct it with a struct literal (User { ... }) AND cannot exhaustively destructure it without .. (let User { username, .. } = u;). Callers must construct it through a pub fn new(...) method, ensuring the module's validation invariants can never be bypassed!