ProgrammingBackend Developer

How is visibility modifier handling (pub, pub(crate), pub(super)) implemented in Rust and how do they differ from modifiers in other languages? What problems can arise from incorrect visibility settings of module items?

Pass interviews with Hintsage AI assistant

Answer.

In Rust, visibility modifiers control access to module items (structures, functions, constants, etc.). By default, everything declared in a module is private (accessible only within that module). There are special modifiers:

  • pub: makes the item public (visible from any external modules).
  • pub(crate): visibility is limited to the current crate (package).
  • pub(super): visibility is limited to the parent module.
  • pub(in path): visibility is limited to a specific path.

Example:

mod foo { pub struct Bar { pub x: i32, // field accessible everywhere y: i32, // field private } pub(crate) fn crate_fn() {} pub(super) fn super_fn() {} fn private_fn() {} }

The main difference from, say, C++ or Java is that there is no separate level for protected, and accessibility is strictly controlled at the module/path level, not the class hierarchy level.

Trick question.

Question: If a structure is declared as pub struct Foo, will its private fields be accessible in another module of the same project?

Common answer: Yes, since the structure is public.

Correct answer: No, only the structure itself (Foo) will be visible, and its fields will only be accessible if they are also declared with the pub modifier. Fields without pub remain private, even if the structure itself is public.

Example:

mod foo { pub struct Bar { pub x: i32, y: i32, } } fn main() { let bar = foo::Bar { x: 1, y: 2 }; // Error: field `y` is inaccessible }

Examples of real errors due to ignorance of the nuances of the topic.


Story

In a large project, a structure was publicly exported using pub, but the fields were left private by default. Other modules could not create instances of the structure directly, and the only solution was to write additional constructors or declare the necessary fields as pub. This caused the API to fail until final adjustments were made.


Story

One of the developers in the library used only pub(crate) for functions, assuming they could be called from binary projects using this library. However, such functions became unavailable in the external binary crate, causing integration issues.


Story

In one of the plugins for the API server, pub(super) was used for structures, but over time there was a need for access to them from other modules; due to the visibility settings, several modules had to be dramatically rewritten to ensure the required scope without breaking encapsulation.