String Formatting in Rust

Rust offers excellent support for string formatting through the format! macro and related macros. Here are some examples of common string formatting tasks.

use std::fmt;

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    // Rust offers several formatting traits for different types.
    // For example, this prints an instance of our `Point` struct.
    let p = Point { x: 1, y: 2 };
    println!("struct1: {:?}", p);

    // If the type implements `Display`, you can use `{}` for basic formatting.
    // For more complex types, you might need to implement `Display` manually.
    impl fmt::Display for Point {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "({}, {})", self.x, self.y)
        }
    }
    println!("struct2: {}", p);

    // To print the type of a value, use `std::any::type_name`.
    println!("type: {}", std::any::type_name::<Point>());

    // Formatting booleans is straightforward.
    println!("bool: {}", true);

    // There are many options for formatting integers.
    // Use `{}` for standard decimal formatting.
    println!("int: {}", 123);

    // This prints a binary representation.
    println!("bin: {:b}", 14);

    // This prints the character corresponding to the given integer.
    println!("char: {}", char::from_u32(33).unwrap());

    // `{:x}` provides lowercase hex encoding, `{:X}` for uppercase.
    println!("hex: {:x}", 456);

    // There are also several formatting options for floats.
    // For basic decimal formatting use `{}`.
    println!("float1: {}", 78.9);

    // `{:e}` and `{:E}` format the float in (slightly different versions of) scientific notation.
    println!("float2: {:e}", 123400000.0);
    println!("float3: {:E}", 123400000.0);

    // For basic string printing use `{}`.
    println!("str1: {}", "\"string\"");

    // To print a representation of a pointer, use `{:p}`.
    println!("pointer: {:p}", &p);

    // When formatting numbers you will often want to control the width and precision.
    // To specify the width, use a number after the `:`.
    println!("width1: |{:6}|{:6}|", 12, 345);

    // You can also specify the width and precision of printed floats.
    println!("width2: |{:6.2}|{:6.2}|", 1.2, 3.45);

    // To left-justify, use the `<` flag.
    println!("width3: |{:<6.2}|{:<6.2}|", 1.2, 3.45);

    // You may also want to control width when formatting strings.
    println!("width4: |{:6}|{:6}|", "foo", "b");

    // To left-justify use the `<` flag as with numbers.
    println!("width5: |{:<6}|{:<6}|", "foo", "b");

    // `format!` returns a String without printing it.
    let s = format!("format!: a {}", "string");
    println!("{}", s);

    // You can format+print to `io::Write` implementations using `write!` or `writeln!`.
    use std::io::Write;
    writeln!(&mut std::io::stderr(), "io: an {}", "error").unwrap();
}

To run the program:

$ cargo run
struct1: Point { x: 1, y: 2 }
struct2: (1, 2)
type: string_formatting::Point
bool: true
int: 123
bin: 1110
char: !
hex: 1c8
float1: 78.9
float2: 1.234e8
float3: 1.234E8
str1: "string"
pointer: 0x7ffd5e8e9850
width1: |    12|   345|
width2: |  1.20|  3.45|
width3: |1.20  |3.45  |
width4: |   foo|     b|
width5: |foo   |b     |
format!: a string
io: an error

This example demonstrates various string formatting techniques in Rust, including formatting for different types, controlling width and precision, and using different output methods. Rust’s formatting system is powerful and flexible, allowing for detailed control over how values are presented as strings.