You’ve seen println!("Hello, world!") already. But why the exclamation mark? In Rust, ! means you’re calling a macro, not a regular function.

Macros vs functions

A regular function in Rust has a fixed number of typed parameters. A macro can accept a variable number of arguments of different types — which is exactly what you need for printing.

println!("Hello");                        // zero args
println!("Hello, {}!", "Rust");           // one arg
println!("{} + {} = {}", 1, 2, 1 + 2);   // three args

If println were a regular function, you’d need a different overload for each case. Instead, macros handle this at compile time.

String formatting: {} and friends

Rust’s formatting is similar to Java’s but without String.format()’s ceremony:

let name = "Priya";
let score = 42;

println!("Player: {}, Score: {}", name, score);
// Output: Player: Priya, Score: 42

A few useful format specifiers:

println!("{:?}", vec![1, 2, 3]);   // debug format → [1, 2, 3]
println!("{:.2}", 3.14159);        // decimal places → 3.14
println!("{:>10}", "right");       // right-align in 10 chars

Other print macros

MacroUse
println!Print with a newline
print!Print without a newline
eprintln!Print to stderr
format!Build a String (like String.format())
dbg!Print variable name + value, return the value

dbg! is especially handy during development:

let x = 5;
let y = dbg!(x * 2) + 1;  // prints: [src/main.rs:3] x * 2 = 10

It’s like adding a System.out.println debug line, but it also tells you the file and line number.