Background:
In languages like C++ or Java, access modifiers (public, private, protected) ensure visibility of class members, but they are quite flexible — and often do not prevent incorrect API usage. In Rust, from early versions, they made the access control system strict and explicitly modular to limit "leakage" of internal details outside.
The Problem:
Structs often need to partially hide themselves from external code: for example, fields are private, while only methods are exposed. If access is not restricted, invariants of the struct can be unintentionally spoiled (for instance, by directly exposing an internal Vec). Reckless publication of a struct makes the API fragile.
The Solution:
In Rust, everything is private by default. The pub keyword is used for explicit exports: you can declare the struct itself as visible, while keeping fields hidden. Methods are declared as pub or private individually. Additionally, non-standard forms like pub(crate) or pub(super) allow fine-tuning of the access level.
Code Example:
mod domain { pub struct User { pub name: String, age: u32, // private field } impl User { pub fn new(name: String, age: u32) -> Self { Self { name, age } } pub fn age(&self) -> u32 { self.age } } } use domain::User; fn main() { let u = User::new("Eve".to_string(), 24); println!("{} {}", u.name, u.age()); // u.age — access error! field is closed outside the module }
Key Features:
Can a struct be pub, but all its fields remain private? How can instances be created outside the module then?
Yes. This is often done: the struct is pub, the fields are private, creation is only through public constructors (for example, pub fn new...).
Will a struct field be visible in the external code when declaring pub struct Foo?
No, by default each field remains private — you need to explicitly declare pub for the field. pub struct only makes the type visible.
Does pub work for enum in the same way?
For enum, pub applies to all variants, but for associated data in variants (e.g., a field inside Variant(value: T)), you still need to explicitly specify pub if you want to make the internals accessible.
In the library, the struct was declared as pub struct Config, all fields also pub — so the user could "see" them. As a result, any external code could arbitrarily change the state, violate invariants, causing a panic out of nowhere.
Pros:
Cons:
The struct Config is pub, all fields are private. For configuration — only through builder methods, default constructor, or setter/getter functions. In the module's context, invariants cannot be broken.
Pros:
Cons: