We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Modules, Visibility, Testing and Docs step 3 of 22
Everything is private by default: the two privacy rules
Everything in Rust is private by default. Not “private to the file” — private to the module it is declared in, plus every module below that one. That asymmetry (children can reach up, parents cannot reach down) is the entire privacy model, and it is worth stating as the Reference states it, because two precise rules replace a lot of folklore.
An item is accessible from module
mif it is public and every ancestor module of it is also accessible fromm.A private item is accessible from the module that declares it and from all of that module’s descendants.
The task
pub fn parse_ratios(pairs: Vec<(i64, i64)>) -> Vec<Option<f64>>
Inside a module named ratio, define:
-
pub struct Ratiowith private fieldsnumandden, -
pub fn new(num: i64, den: i64) -> Option<Self>, returningNonewhen the denominator is zero, -
pub fn value(&self) -> f64, the quotient as a float.
parse_ratios lives at the crate root — outside ratio — and maps each pair
through new and value, yielding None for any pair new rejected.
The starter compiles nothing, on purpose
The module is written for you and every item in it is private. parse_ratios
sits one level up and cannot see a thing, so you get a wall of E0603 — is
private. That is the error you want to be able to read fluently: it means the
path is right and the visibility is wrong.
The temptation is to sprinkle pub until the noise stops. Resist it for thirty
seconds and ask which three things are genuinely part of this module’s interface
— and, separately, which are not. The fields are not. Adding pub to num and
den also makes the code compile, and it destroys the only thing this design
was for.
Why private fields matter here
With private fields, Ratio cannot be constructed from outside ratio by any
route at all — not by a struct literal, not by ..Default::default(), not by
accident. The only door is new, and new refuses a zero denominator.
Therefore no Ratio value anywhere in the program can have a zero
denominator, and value never has to check. That is what people mean by “the
type makes illegal states unrepresentable”, and it is enforced by the compiler
rather than by a comment.
Make num and den public and the guarantee evaporates: any caller can write
Ratio { num: 1, den: 0 } and value starts returning infinity from a function
that promised it wouldn’t.
A note about grading. The runtime tests here cannot see whether your fields are private — they only observe the numbers coming out, and a version with public fields produces the same numbers. What is being graded is the behaviour; what is being taught is the design. This is one of the places where you have to hold yourself to the standard, because the test cannot.
Two smaller notes for the write-up:
-
Privacy is not file-local. A private helper in
mod engineis fully visible tomod engine::internals, becauseinternalsis a descendant. If you are used to Java-style package privacy this feels leaky; it is deliberate, and it is why “extract the guts into a submodule” is a safe refactor in Rust. -
pubon a struct does not make its fields public. Structs and their fields have independent visibility, and so do enum variants’ — except that enum variants are always as public as their enum.
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.