We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Generics and Traits step 6 of 24
Format money with Display
Implement std::fmt::Display for the supplied Money type. Replace the
starter's direct ToString implementation, and keep render calling
.to_string() on each Money value.
pub struct Money { pub cents: i64 }
pub fn render(cents: Vec<i64>) -> Vec<String>
Required format
Each input is an integer number of cents, anywhere in the i64 range. Return one string per input, preserving order and duplicates. Empty input produces an empty vector.
Put $ before the whole-dollar amount, commas between groups of three
whole-dollar digits, and exactly two digits after the decimal point.
Negative amounts have a minus sign before $. Do not add a plus sign,
spaces or a newline. Use these fixed symbols regardless of locale.
| Cents | Output |
|---|---|
123456 |
$1,234.56 |
0 |
$0.00 |
5 |
$0.05 |
-123456 |
-$1,234.56 |
100000000 |
$1,000,000.00 |
i64::MIN |
-$92,233,720,368,547,758.08 |
This exercise requires plain {} formatting and .to_string(). Support
for extra width, alignment, precision or other formatting flags is outside
the task. No floating-point conversion or rounding is needed.
Display also supplies ToString
Rust's formatting traits include Display for {} and Debug for {:?},
as well as traits for formats such as binary and hexadecimal. Debug is
commonly derived for diagnostics. Display describes a chosen text format;
there is no built-in Display derive, although external macros can generate
implementations.
The standard library implements ToString for types that implement Display, including unsized types. This is a blanket implementation: it applies to every type meeting its bound. It provides the method automatically, not an allocation-free conversion. See the ToString documentation.
Here is a complete example with a simpler format:
use std::fmt;
struct Count(u32);
impl fmt::Display for Count {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} items", self.0)
}
}
fn main() {
let count = Count(3);
assert_eq!(count.to_string(), "3 items");
assert_eq!(format!("Count: {count}"), "Count: 3 items");
}
A direct ToString implementation is possible for a type without Display,
but Clippy recommends implementing Display instead. Keeping both would
conflict with the standard library's blanket implementation. An inherent
to_string method is also discouraged and can shadow the trait method.
Remove the starter's direct implementation rather than adding Display
beside it. Its todo!() also panics when a nonempty input reaches it.
Handle the smallest negative value
i64::MIN has no positive counterpart in i64. Negating it or taking its
signed absolute value overflows. With overflow checks enabled this panics;
with checks disabled it wraps. Optimization alone does not guarantee which
behavior a build uses, since overflow checks can be configured explicitly.
Use cents.unsigned_abs() to obtain the magnitude as u64. Divide by 100
for whole dollars and take the remainder modulo 100 for cents. Group the
whole-dollar decimal digits from the right. Format the remainder with :02
to retain a leading zero when needed.
Write fields and propagate errors
Within Money's Display implementation, write!(f, "{}", self) would call
that same implementation again. Format the magnitude and sign instead.
Clippy's recursive_format_impl detects this direct recursion.
Each write returns fmt::Result. Propagate intermediate errors with ?
and return the final write's result. A failing destination is an error;
a valid negative amount is not. Do not add a newline to this exercise's
output. See Display's error contract.
Passing requires correct output, compilation and Clippy with warnings treated as errors.
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.