pubKeyword
Explanation
pub widens an item's default visibility, which is otherwise private —
reachable only from the module that defines it and that module's
descendants. Written alone before an item (pub fn, pub struct,
pub mod, pub use, …), it removes that restriction entirely: the item
is visible from anywhere that can reach the module defining it, including
outside the crate, provided the module path leading to it is itself
public.
Four scoped forms narrow that ceiling instead of removing it outright:
pub— no restriction beyond ordinary module-tree reachability.pub(crate)— visible anywhere in the same crate, never outside it. The most common scoped form: it shares an item across a crate's own modules without adding it to the crate's public API.pub(super)— visible to the parent module (and transitively, anywhere the parent's own visibility already reaches). Shorthand forpub(in <parent path>).pub(in some::path)— visible only withinsome::pathand that path's descendant modules.some::pathmust name an ancestor module of the item being marked — this form can only restrict how far down an already-reachable subtree the boundary is drawn, never grant visibility to a module that couldn't already see the item.pub(crate)andpub(super)are convenience shorthands for the two most common ancestors: the crate root, and the immediate parent.
On a struct, pub (in any form) applies per field, not automatically to
the whole struct: pub struct Point { pub x: i32, y: i32 } makes the
struct name itself visible while x is public and y stays private. See
Visibility & privacy
for the design rationale behind this kind of partial exposure — this page
covers the grammar of pub and its scoped forms.
Usage examples
Making a struct and field visible outside its module
mod billing {
pub struct Invoice { // <- `pub`: visible outside the `billing` module
pub total_cents: u64,
}
}
let invoice = billing::Invoice { total_cents: 4200 };
Designing a public API
A cache crate splits its storage and eviction logic into separate
modules that need to share an internal entry type — pub(crate) lets them
do that without the type ever becoming part of the crate's public API.
pub mod api { // <- plain `pub`: visible from outside the crate entirely
pub(crate) mod internal { // <- `pub(crate)`: visible anywhere in this crate, not outside it
pub(super) fn raw_encode(bytes: &[u8]) -> Vec<u8> {
// <- `pub(super)`: visible only to `api`, the parent module
bytes.to_vec()
}
pub(in crate::api) fn checksum(bytes: &[u8]) -> u32 {
// <- `pub(in path)`: visible only within `api` and its descendants
bytes.iter().map(|b| *b as u32).sum()
}
}
pub fn encode(bytes: &[u8]) -> Vec<u8> {
internal::raw_encode(bytes) // reachable: `api` is `internal`'s parent module
}
}
Each scoped form draws the visibility boundary at
exactly the module that needs it — pub(crate) shares internal across
the crate, pub(super)/pub(in path) narrow individual functions further
still — so nothing here is visible any wider than the code that actually
uses it requires, matching the general shrink-visibility-first stance in
the
API Guidelines' future-proofing chapter.
Validating input
A Temperature type must never represent a value below absolute zero, so
its field stays private and pub is applied only to the constructor and
the read accessor, not the field itself.
pub struct Temperature {
celsius: f64, // private: no outside code can set an invalid value directly
}
impl Temperature {
pub fn from_celsius(value: f64) -> Result<Self, &'static str> {
// <- `pub`: the only public entry point that can construct one
if value < -273.15 {
return Err("temperature below absolute zero");
}
Ok(Temperature { celsius: value })
}
pub fn celsius(&self) -> f64 { // <- `pub`: read-only access, no bypass of the check above
self.celsius
}
}
Applying pub to the constructor and getter but not the
field means "never below absolute zero" is enforced by the type itself,
which is exactly what the
API Guidelines' C-STRUCT-PRIVATE
item recommends private fields for.