Course contentsShow
← Rust
Lesson 501 of 1,9105. Type System and TraitsFree lesson

The Impact of Visibility Modifiers on Type API

Control module boundaries and encapsulation by restricting type access.

In this lesson, you will learn how visibility modifiers act as the "gatekeepers" of your library’s API, determining which parts of your type system are exposed to the outside world.

The Power of Encapsulation

In Rust, everything is private by default. When you define a struct or an enum, its fields and variants are hidden from other modules unless you explicitly mark them as pub. This isn't just about security; it’s about API stability. By keeping internal details private, you retain the freedom to change your internal implementation without breaking the code that depends on your library.

Controlling the Gate

Consider a scenario where you are building a BankAccount. If you expose the internal fields directly, users could modify the balance in ways that violate your business rules.

mod banking {
    pub struct Account {
        // This field is private! Even if the struct is pub,
        // code outside this module cannot touch `balance`.
        balance: f64,
    }

    impl Account {
        pub fn new(initial: f64) -> Self {
            Self { balance: initial }
        }

        pub fn deposit(&mut self, amount: f64) {
            self.balance += amount;
        }
    }
}

By keeping balance private, you force users to interact with your type through the public API (deposit). If you decide later to change balance from an f64 to a Decimal type to improve precision, you can do so safely. Because the outside world never touched the field directly, their code remains perfectly functional.

Structs vs. Fields

Remember that a pub struct does not automatically make its fields public. You must mark each field individually if you want to expose it. This is a deliberate choice: by defaulting to private, Rust encourages you to design a "contract" for your types. You define what the user is allowed to do, and you hide the "how" inside the module boundaries. This separation ensures that your type's internal state remains consistent and easy to debug.

Key Takeaway: Visibility modifiers are your primary tool for defining a clean API boundary; by keeping implementation details private, you ensure your code remains maintainable and resistant to breaking changes.