Visibility

Make your Code Items Public with the pub Keyword

book-rust-by-example-visibility-rules

In Rust, all items (modules, functions, methods, structs, enums, constants...) are private by default.

Use the pub keyword before an item's definition to make it public:

/// Private module.
mod m {
    /// Private function.
    fn private_function() {}

    /// Public function.
    pub fn public_function() {}

    /// Public unit-like struct.
    pub struct Struct;

    impl Struct {
        /// Public method.
        pub fn method(&self) {}
    }

    /// Public trait.
    pub trait Trait {}

    /// Trait implementation.
    /// `pub` is not allowed here.
    impl Trait for Struct {}

    /// Private submodule.
    mod private_module {}

    /// Public submodule.
    pub mod public_module {}
}

fn main() {
    // Access the public function within module `m`:
    m::public_function();
    // ERROR: m::private_function();

    // Access the public struct and trait.
    let _t: &dyn m::Trait = &m::Struct;

    // Access the public method.
    m::Struct.method();
    // Equivalent to m::Struct::method(&m::Struct);

    // Bring the public submodule into scope.
    use m::public_module;
    // ERROR: use m::private_module;
}

There are two exceptions to the "privacy by default" rule: Enum variants in a pub enum are public by default. Associated items (incl. functions and methods) in a pub are also public by default.

Also note that, if we use pub before a struct definition, we make the struct public, but the fields of the struct will still be private. Mark relevant fields with pub:

mod a_module {

    /// Public enum.
    pub enum Enum {
        // Public-by-default variant.
        Variant,
    }

    /// Public struct with a private field.
    pub struct PublicStruct {
        private_val: bool,
    }

    impl PublicStruct {
        /// Public associated function ("constructor").
        pub fn new(val: bool) -> Self {
            Self { private_val: val }
        }
    }

    /// Public struct with a public field.
    pub struct PublicStructPublicField {
        pub public_val: bool,
    }

    /// Public trait.
    pub trait Trait {
        type Out; // Public-by-default associated type.
        // Visibility qualifiers are not permitted below:
        fn method(&self) -> Self::Out;
    }
}

fn main() {
    let _ = a_module::Enum::Variant;
    let _ = a_module::PublicStructPublicField { public_val: true };

    // As we will see below, we can't access `private_val`,
    // but we can use its public associated function to create the struct:
    // ERROR: let _ = a_module::PublicStruct { private_val: true };
    let _ = a_module::PublicStruct::new(false);
}

As discussed below, the scope where an item is visible can be specified after the pub keyword: pub(crate), pub(super), pub(in path)...

Make your Code Items Accessible (Visibility Rules)

Rust visibility rules are as follows:

  • If an item is private, it may be accessed by the current module and its descendants only.
fn private_in_parent() {}

mod private_module {
    fn also_private() {
        // `private_in_parent` is accessible,
        // since it is in a parent module.
        super::private_in_parent();
    }
    mod submodule {}
}

fn main() {
    // `private_in_parent` is accessible, since it is
    // in the same module than `main`.
    private_in_parent();

    // `private_module` is accessible as well,
    // because it is also in the same module...
    use private_module as alias;

    // ...but its private contents are not!
    // ERROR: private_module::also_private();
    // ERROR: alias::also_private();
    // ERROR: use private_module::submodule;
}
  • If an item is public, then it can be accessed externally from some module m, if you can access all the item's ancestor modules from m.

In other words,

  • Items can access other items in the same module, even if private.
  • Items in a parent module can't use private items inside child modules (encapsulation).
  • Items in child modules can use all items in their ancestor modules.
mod a_module {
    fn private() {}
    pub fn public() {}

    pub mod public_nested_module {
        fn private() {}
        pub fn public() {}
    }

    mod private_nested_module {
        fn private() {}
        pub fn public() {}
    }
}

fn main() {
    // For an item to be accessible, all elements in the paths
    // must be accessible from the current module.
    a_module::public();

    // Here, `a_module` is accessible, despite being private,
    // because it is in the same module than `main`.

    // No access, if one or more segments in the path are inaccessible.
    // Here, `private` can't be reached from a parent.
    // ERROR: a_module::private();

    a_module::public_nested_module::public();
    // ERROR: a_module::public_nested_module::private();
    // ERROR: a_module::private_nested_module::private();
    // ERROR: a_module::private_nested_module::public();
}

// The same applies when calling from a brother module.
mod another_module {
    fn call() {
        // `super` refers to the parent and is therefore accessible
        // from the child.
        super::a_module::public();
        // ERROR: super::a_module::private();
        super::a_module::public_nested_module::public();
        // ERROR: super::a_module::private_nested_module::public();
    }
}

More precisely, an item is accessible if all segments in its path are accessible. That means that all enclosing modules traversed in the "parent to child" direction must be pub with the appropriate visibility scope (see below), or, if an enclosing module is not, there must be a suitable reexport - see the pub use section of theuse Keyword chapter for more details.

Make your Code Items Visible to your Library's Clients

A library developer needs to expose functionality to crates which link against their library. Anything which is usable externally must be pub from the crate root down to the destination item. Any private item in the chain will disallow external accesses.

In particular, that means marking the relevant modules in the crate root (e.g. lib.rs) as pub.

//! In the crate root:

// This function is available to external code using this crate as a dependency.
pub fn public_to_external_crates() {}

// This module is public, so external crates may look inside of it,
// and access the inner public function:
pub mod public_api {
    pub fn also_public_to_external_crates() {}
}

// In constrast, this module is private, meaning that no external crate can
// access this module. It is however accessible from the current module and any
// descendants. If it is private at the root of this current crate, any module
// in the crate may access any publicly visible item in this module.
mod crate_helper_module {
    pub fn crate_helper() {}
}

fn main() {
    crate_helper_module::crate_helper();
}

Limit the Visibility of an Item to a Given Scope

You can declare an item (type, function, module...) as visible only within a given scope by prefixing it with pub(crate), pub(super) or pub(in path) rather than just pub:

  • pub(crate) makes an item visible within the current crate only.
  • pub(super) makes an item visible to the parent module only.
  • pub(in path) makes an item visible within the provided path, which must start with crate, self, or super and resolves to an ancestor module of the item whose visibility is being declared. This form is seen infrequently.

The following demonstrates this syntax:

mod a {
    pub mod b {
        pub(crate) fn visible_in_crate() {}
        pub(super) fn visible_in_parent_module() {}
        pub mod c {
            pub(in super::super) fn visible_in_a() {}
        }
    }

    #[allow(dead_code)]
    fn use_in_a() {
        b::visible_in_crate();
        b::visible_in_parent_module();
        b::c::visible_in_a();
    }
}

mod d {
    #[allow(dead_code)]
    fn use_in_d() {
        super::a::b::visible_in_crate();
        // ERROR: super::a::b::visible_in_parent_module();
        // ERROR: super::a::b::c::visible_in_a();
    }
}

fn main() {
    a::b::visible_in_crate();
    // ERROR: a::b::visible_in_parent_module();
    // ERROR: a::b::c::visible_in_a();
}

When writing a library or in contexts where the public API must remain stable, pub(crate) and related forms are safer to use than pub alone, in the sense they are a safeguard against accidentally making an item fully public to external crates linking the library.

// In e.g. `lib.rs`:
mod a_module {
    // Conservative use of `pub(crate)`:
    // Even if `a_module` is accidentally made fully public,
    // this function will remain visible only to this crate.
    pub(crate) fn visible_in_crate_only() {}
}

// You can also explictly mark the top module as `pub(crate)`:
pub(crate) mod b_module {
    pub fn visible_in_crate_only() {}
}

fn main() {
    a_module::visible_in_crate_only();
    b_module::visible_in_crate_only();
}

References