We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Shape Your Data: Structs, Enums, Pattern Matching step 25 of 26
Protect rectangle invariants with private fields
The shape module validates rectangle dimensions before storing them.
Keep its fields private and add a public method for calculating area, so
callers can use a rectangle without accessing its representation.
Required behavior
Both functions receive (width, height) pairs:
rect_areas(dims: Vec<(i64, i64)>) -> Vec<Option<u64>>returnsSome(width * height)for valid dimensions andNoneotherwise.orientations(dims: Vec<(i64, i64)>) -> Vec<String>returns"portrait"when width is smaller than height,"landscape"when width is larger, and"square"when they are equal. Invalid dimensions produce"invalid".
Both sides must be between 1 and u32::MAX, inclusive. Validate both
before calculating an area or orientation. Keep the input order and return
one result per pair, including duplicates. Empty input produces an empty
vector from each function.
For [(3, 4), (5, 5), (0, 2)], the areas are
[Some(12), Some(25), None] and the orientations are
["portrait", "square", "invalid"]. The harness serializes None as
JSON null.
Fix the private-field error
Rect is public, but its w and h fields are private. The starter
tries to read them from rect_areas, outside the shape module.
Rust reports E0616.
Add pub fn area(&self) -> u64 to the existing impl Rect inside
shape, then call it from rect_areas. Keep Rect::new and
orientation working as supplied. Making the fields public would avoid
the compiler error but would not meet this exercise's API requirement.
Convert each side to u64 before multiplying. The largest valid product
is u32::MAX squared, or 18_446_744_065_119_617_025, which fits in
u64. Multiplying as u32 first could overflow.
What privacy protects
An invariant is a condition that valid values of a type must satisfy.
Here it is “both sides are positive.” Private fields prevent callers
outside shape and its descendants from constructing or modifying those
fields directly. Constructing a Rect literal there produces E0451.
Privacy makes the module responsible for preserving the invariant. Code inside the module and its child modules can still access the fields, so every constructor and mutating method exposed by the module must preserve the rule. Adding an unchecked constructor or a mutable field accessor would weaken that guarantee.
Private fields are not the only way to express invariants. For example,
NonZeroU32 represents a nonzero integer in its type. Public fields still
obey their field types; what they cannot enforce on their own is an extra
rule such as a relationship between two unrestricted integer fields.
Struct and enum visibility
A public struct's fields remain private unless given their own visibility.
Enum variants and their fields inherit the enum's visibility instead.
That is why orientations can match shape::Orientation::Portrait
even though it cannot read rect.w.
Public fields on an enum variant do not imply public access to private fields inside a separate struct carried by that variant. An API can use such a struct to expose a variant while keeping its payload's representation private.
Struct update syntax, such as Rect { ..existing }, does not bypass
private-field checks. A Default implementation does not change that.
Visibility also depends on the path used to reach an item. A public item
inside a private module can be used from scopes that can access that
module, as this starter demonstrates. A public re-export can give an
item another accessible path. Restricted forms include pub(crate)
for the current crate, pub(super) for the parent module and its
descendants, and pub(in path) for a specified ancestor module's scope.
Validation and conversion are separate
u32::try_from rejects negative inputs and values above u32::MAX,
but accepts zero. The constructor's w > 0 && h > 0 guard supplies the
extra check this type needs. A cast such as w as u32 would not validate
the input; for example, -1_i64 as u32 is u32::MAX.
The submission must compile, pass the output cases and pass Clippy with warnings denied. Output cases alone do not prove that the fields stayed private, so preserve the module boundary as part of the implementation.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.