Visibility

Visibility controls from where items can be accessed and is specified with the keyword. It is the core mechanism to enable encapsulation in the module system.

Encapsulation means that every crate and every module exposes a public API, whereas implementation details are hidden and can be modified freely without breaking backwards compatibility. If something is private, you can rest assured that it will never be used outside of its module. Encapsulation enables local reasoning: The implementation details of one module don't affect the implementation details of another module. This is crucial for the correctness of both safe and unsafe code.

One example of this are the fields of the type. If the fields could be modified from anyone, they could be set to incorrect values, leading to Undefined Behavior and possibly security vulnerabilities. But since the fields are private, they can only be modified in the  module. Because this code has been carefully reviewed, we can be confident that the length and capacity of a  is always correct.

Accessability and visibility of items
If an item is visible, that doesn't imply that it can be accessed. An item is accessible in a module m if two conditions are satisfied:


 * The item is visible in m
 * A path to the item exists that is visible in m

If no visible path to the item exists, it is inaccessible, even if the item itself is visible. The visibility is only the maximum scope where the item can be accessed:

In this example, both  and   are public, but   isn't publicly exported. The path can't be accessed, because the   module isn't visible outside of the enclosing module.

Default visibility
Most types of items are private by default; this visibility is chosen when no visibility modifier is specified. Private items can only be accessed within the current module (including its child modules). It can not be accessed in parent or sibling modules, or in different crates:

There are exceptions, however. Enum variants, enum fields, macros and associated items of traits are always public. They can't be made private, so they are always accessible, if they are exported:

Public visibility
If an item is public, it is visible everywhere in the current crate, as well as outside of the crate:

Visibility in a specific module
All items that aren't public are visible in exactly one module. For example, private items are only visible in the module where they were defined. The visibility is specified with the syntax, where   is a path to the current module  or any of its ancestors:

Since this is quite verbose, it can be abbreviated:


 * , and  can be abbreviated with,  and , respectively. These three paths are special-cased, because they are so common.
 * means that the item is private (it is only visible in the current module), which is the default, so the visibility modifier can be omitted.

As a result, the above is equivalent to this code:

Note that the specified path must refer to the current module or one of its ancestors:

Visibility and exporting
Items are exported with the keyword (except macros). Rust prevents you from exporting an item to a module where it isn't visible:

However, it doesn't prevent you from making an item public, even if it isn't exported anywhere:

The above code contains a public function returning a public struct. However, the struct is in a private module, which means that it is not accessible outside of this module. Therefore, the function  can be called from anywhere, but it's return type can't be named outside of this crate:

Note that  must be public in order to be used in a public function:

This ensures that implementation details never “leak“ into the public API: Anything that can be observed from another crate must be public.

Historic note about
The  keyword of  can't be omitted, unless   is either,  or. Although proposed the syntax, this would have caused syntactic ambiguity, so it was decided to use the more explicit  syntax.

Experimental features
allows replacing with just. The RFC has been accepted and implemented, but the visibility modifier is still an unstable feature:

The motivation for this is to make code more concise and readable.