Step 6 of 7
Formatting: width, alignment, precision
Inside {} you can add a format spec after a colon: {:>8}, {:.2}, {:08.3}. It controls width, alignment, padding, precision, sign and number base. It works the same in println!, format!, write! and panic!.
fn main() {
let rows = [("Crab plush", 4, 12.5), ("Rust mug", 12, 9.99), ("Sticker", 150, 0.5)];
println!("{:<12}|{:>5}|{:>8}", "item", "qty", "price");
println!("{}", "-".repeat(27));
for (name, qty, price) in rows {
println!("{:<12}|{:>5}|{:>8.2}", name, qty, price);
}
}
item | qty| price
---------------------------
Crab plush | 4| 12.50
Rust mug | 12| 9.99
Sticker | 150| 0.50
{:<12}pads to width 12, aligned left;{:>5}aligns right;{:^9}centers.{:>8.2}combines width 8 with precision 2 (two decimals).- Without an alignment, text is left-aligned and numbers right-aligned.
- The width is a minimum: a longer value is printed in full, never cut.
The rest of the toolbox
fn main() {
println!("[{:^9}]", "crab");
println!("[{:*<8}]", "ok");
println!("[{:05}]", 42);
println!("[{:+}] [{:+}]", 7, -7);
println!("{:x} {:X} {:#x} {:o}", 255, 255, 255, 8);
println!("{:b} {:#010b}", 5, 5);
let width = 8;
println!("[{:>width$.2}]", 3.14159);
let name = "ana";
println!("[{name:>6}] [{:.3}]", "crabby");
}
[ crab ]
[ok******]
[00042]
[+7] [-7]
ff FF 0xff 10
101 0b00000101
[ 3.14]
[ ana] [cra]
| Spec | Meaning |
|---|---|
{:*<8} |
fill character * (any char), then alignment and width |
{:05} |
pad a number with zeros to width 5 |
{:+} |
always show the sign |
{:x} {:X} {:o} {:b} |
hexadecimal (lower/upper), octal, binary |
{:#x} {:#b} |
with the 0x / 0b prefix (the prefix counts toward the width) |
{:>width$} |
width taken from a variable named width |
{name:>6} |
inline argument with a spec |
{:.3} on text |
at most 3 characters: the one way to cut text in a format |
Width counts chars, not bytes, so é takes one column. (Emoji and CJK characters often take two columns on screen, which format! can't know about.)
Common mistakes
{:2}versus{:.2}. The first is a width of 2; the second is 2 decimals.- Expecting a narrow width to truncate.
{:3}on"crabby"prints all six letters. Use{:.3}to cut. - Money in floats.
0.1 + 0.2isn't exactly0.3in binary floating point. Formatting with{:.2}hides it on screen, but real billing code stores whole cents in integers.
Your task
Print a receipt table. Each input line is name,qty,unit_price (prices with decimals). Print a header, a separator, one row per item with its line total (qty times unit price), another separator and the grand total, laid out like this:
item qty price total
-----------------------------------
Crab plush 4 12.50 50.00
Rust mug 12 9.99 119.88
-----------------------------------
total 169.88
Columns: item left-aligned in 12, qty right-aligned in 5, price and total right-aligned in 9 with 2 decimals. The separator is 35 dashes; the last line is total left-aligned in 26 followed by the grand total right-aligned in 9 with 2 decimals.
Challenge 2
Fill in the four format specs so the program prints exactly:
[ right]
[ mid ]
[0003.142]
[0xbeef]
Challenge 3
Write fn progress_bar(done: u32, total: u32, width: usize) -> String for a command-line tool. The percentage is done * 100 / total (rounded down; treat total == 0 as 100%). The bar has width characters: width * percent / 100 of them #, the rest -. After the bar comes a space and the percentage right-aligned in 3 columns, then %:
[#####-----] 50%