RustArena

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

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

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%

Previous: Building strings Next: Display versus Debug