Visibility in Rust (purpose)
Different types of visibility in Rust
Rust code example + output (shows multiple visibility kinds)
Java code example + output (shows multiple visibility kinds)
Struct visibility
Tabular summary of visibility (Rust vs Java)
Visibility in Rust (purpose)
Visibility controls who can access what (structs, functions, modules, fields).
It helps you:
Hide internal implementation (encapsulation)
Expose only stable APIs to other modules/crates
Prevent accidental misuse of private helpers
Organize large projects cleanly with modules and crates
Rust is private by default: anything you define is only accessible inside the same module unless you make it public.
Different types of visibility in Rust
1) private (default)
Accessible only inside the same module (and its child modules can’t access it unless it’s in scope rules; generally: items are private to the module).
2) pub
Accessible from anywhere that can reach the module path (outside module + outside crate too).
3) pub(crate)
Accessible anywhere inside the same crate, but not outside the crate.
4) pub(super)
Accessible to the parent module of the current module.
5) pub(in path)
Accessible only inside a specific module path (like “friend access” scoped to a subtree).
Important related rule (very common confusion)
If a module is private, then even pub items inside it are not reachable from outside.
You must make the module itself pub too if you want external access.
Rust code example + output (shows multiple visibility kinds
mod company {
pub mod hr {
// Visible everywhere
pub fn public_policy() {
println!("HR: public policy (pub)");
}
// Visible only inside this crate
pub(crate) fn internal_policy() {
println!("HR: internal policy (pub(crate))");
}
// Visible only to parent module: company
pub(super) fn policy_for_company() {
println!("HR: policy for company module (pub(super))");
}
// Private (default): only inside hr
fn secret_notes() {
println!("HR: secret notes (private)");
}
// Visible only inside `company` module tree
pub(in crate::company) fn company_only_policy() {
println!("HR: company-only policy (pub(in crate::company))");
}
pub fn demo_inside_hr() {
secret_notes(); // ✅ allowed (same module)
}
}
pub fn demo_inside_company() {
// ✅ company is parent of hr, so pub(super) works
hr::policy_for_company();
// ✅ pub(in crate::company) works inside company
hr::company_only_policy();
// ✅ pub(crate) works inside crate
hr::internal_policy();
// ✅ pub works
hr::public_policy();
// ❌ private function not accessible here:
// hr::secret_notes();
}
}
fn main() {
// Accessible because hr is pub and function is pub
company::hr::public_policy();
// Accessible because pub(crate) and we're in same crate (main is same crate)
company::hr::internal_policy();
// Not accessible because pub(super) only to parent module (company), not to main:
// company::hr::policy_for_company();
// Not accessible because pub(in crate::company) only within company module tree:
// company::hr::company_only_policy();
// But company can call them internally:
company::demo_inside_company();
// This calls private inside hr indirectly:
company::hr::demo_inside_hr();
}
✅ Expected Output
HR: public policy (pub)
HR: internal policy (pub(crate))
HR: policy for company module (pub(super))
HR: company-only policy (pub(in crate::company))
HR: internal policy (pub(crate))
HR: public policy (pub)
HR: secret notes (private)
Rust (public vs private)
By default, items are private to the module.
Use pub to make them accessible outside the module.
mod account {
pub fn public_fn() {
println!("public_fn called");
}
fn private_fn() {
println!("private_fn called");
}
pub fn call_private_inside() {
private_fn(); // OK: same module
}
}
fn main() {
account::public_fn();
account::call_private_inside();
// account::private_fn(); // ❌ error: private
}
Output
public_fn called
private_fn called
Same program idea in Java (visibility)
Java visibility is mainly at class/member level:
private → only inside the same class
(default) package-private → only inside same package
protected → same package + subclasses
public → everywhere
✅
Java code example + output (shows multiple visibility kinds)
public class Main {
static class Company {
static class HR {
public static void publicPolicy() {
System.out.println("HR: public policy (public)");
}
// package-private (default): same package only
static void internalPolicy() {
System.out.println("HR: internal policy (package-private)");
}
protected static void policyForCompany() {
System.out.println("HR: policy for company (protected)");
}
private static void secretNotes() {
System.out.println("HR: secret notes (private)");
}
public static void demoInsideHR() {
secretNotes(); // ✅ allowed
}
}
public static void demoInsideCompany() {
HR.policyForCompany(); // ✅ allowed (same outer context/package)
HR.internalPolicy(); // ✅ allowed (same package)
HR.publicPolicy(); // ✅ allowed
// HR.secretNotes(); // ❌ not allowed (private)
}
}
public static void main(String[] args) {
Company.HR.publicPolicy(); // ✅
Company.HR.internalPolicy(); // ✅ (same file/package)
Company.demoInsideCompany(); // ✅
Company.HR.demoInsideHR(); // ✅ (calls private internally)
}
}
✅ Expected Output
HR: public policy (public)
HR: internal policy (package-private)
HR: policy for company (protected)
HR: internal policy (package-private)
HR: public policy (public)
HR: secret notes (private)
Java (public / private)
Visibility is controlled using public, private, protected, package-private (no keyword).
class Account {
public void publicFn() { System.out.println("publicFn called"); }
private void privateFn() { System.out.println("privateFn called"); }
public void callPrivateInside() {
privateFn(); // OK: inside same class
}
}
public class Main {
public static void main(String[] args) {
Account a = new Account();
a.publicFn();
a.callPrivateInside();
// a.privateFn(); // ❌ error: private
}
}
Output
publicFn called
privateFn called
Struct visibility
Rust (struct fields are private by default)
You can make the struct public, but its fields stay private unless marked pub.
mod models {
pub struct Person {
pub name: String, // public field
age: u32, // private field
}
impl Person {
pub fn new(name: &str, age: u32) -> Self {
Self { name: name.to_string(), age }
}
pub fn age(&self) -> u32 { self.age } // public getter
}
}
fn main() {
let p = models::Person::new("Ashwani", 30);
println!("name={}", p.name);
println!("age={}", p.age());
// println!("{}", p.age); // ❌ private field
}
Output
name=Ashwani
age=30
Java (fields can be private; access via getters)
class Person {
public String name;
private int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() { return age; }
}
public class Main {
public static void main(String[] args) {
Person p = new Person("Ashwani", 30);
System.out.println("name=" + p.name);
System.out.println("age=" + p.getAge());
// System.out.println(p.age); // ❌ private
}
}
Output
name=Ashwani
age=30
Top comments (0)