Output and Formatting
11 min read
Learn how to print output in Rust using the println! macro and its powerful formatting capabilities.
Quick Overview
Section titled “Quick Overview”Rust uses macros for printing:
println!()- Print with newlineprint!()- Print without newline- Format strings use
{}placeholders - Rich formatting options built-in
Similar to Python’s f-strings or C’s printf!
TypeScript/JavaScript Example
Section titled “TypeScript/JavaScript Example”// Simple printingconsole.log("Hello, world!");
// With variablesconst name = "Alice";const age = 30;
// Template literalsconsole.log(`Hello, ${name}!`);console.log(`${name} is ${age} years old`);
// Multiple valuesconsole.log("Name:", name, "Age:", age);
// Formatting numbersconst pi = 3.14159;console.log(pi.toFixed(2)); // "3.14"
// Objectsconst user = { name: "Bob", age: 25 };console.log(user); // { name: 'Bob', age: 25 }console.log(JSON.stringify(user)); // {"name":"Bob","age":25}TypeScript uses template literals and method calls.
Rust Equivalent
Section titled “Rust Equivalent”// Simple printingprintln!("Hello, world!");
// With variableslet name = "Alice";let age = 30;
// Format stringsprintln!("Hello, {}!", name);println!("{} is {} years old", name, age);
// Inline capture (placeholder names a variable in scope)println!("Hello, {name}!");
// Named arguments (placeholder maps to an explicit value)println!("Hello, {who}!", who = name);
// Formatting numberslet pi = 3.14159;println!("{:.2}", pi); // "3.14"
// Debug formattinglet user = ("Bob", 25);println!("{:?}", user); // ("Bob", 25)
// Pretty debugprintln!("{:#?}", user);Rust uses macros with powerful format strings.
Detailed Explanation
Section titled “Detailed Explanation”Basic Printing
Section titled “Basic Printing”fn main() { // Print with newline println!("Hello!"); println!("World!");
// Print without newline print!("Hello, "); print!("World!\n");
// Print to stderr eprintln!("Error message!");}Output:
Hello!World!Hello, World!Error message!Placeholders
Section titled “Placeholders”fn main() { let name = "Alice"; let age = 30;
// Positional println!("{} is {} years old", name, age);
// Indexed println!("{0} is {1} years old", name, age); println!("{1} is the age of {0}", name, age); // Reorder!
// Inline capture (names a variable already in scope) println!("{name} is {age} years old");
// Named arguments (the placeholder maps to a value you pass) println!("{who} is {years} years old", who = name, years = age);
// Mixed positional and named println!("{0} is {years} years old", name, years = age);}Compare to TypeScript:
const name = "Alice";const age = 30;
// Template literalsconsole.log(`${name} is ${age} years old`);
// Only sequential order possibleDisplay vs Debug
Section titled “Display vs Debug”Display ({}) - Human-readable output:
let x = 42;let s = "hello";let b = true;
println!("{}", x); // 42println!("{}", s); // helloprintln!("{}", b); // trueDebug ({:?}) - Programmer-friendly output:
let tuple = (1, "hello", true);let vec = vec![1, 2, 3];
// println!("{}", tuple); // Error: tuples don't implement Displayprintln!("{:?}", tuple); // (1, "hello", true)println!("{:?}", vec); // [1, 2, 3]Pretty Debug ({:#?}) - Formatted debug:
let data = vec![ ("Alice", 30), ("Bob", 25), ("Charlie", 35),];
println!("{:#?}", data);Output:
[ ( "Alice", 30, ), ( "Bob", 25, ), ( "Charlie", 35, ),]Number Formatting
Section titled “Number Formatting”let pi = 3.14159;
// Decimal placesprintln!("{:.2}", pi); // 3.14println!("{:.4}", pi); // 3.1416
// Width and alignmentprintln!("{:10}", 42); // " 42" (right-aligned)println!("{:<10}", 42); // "42 " (left-aligned)println!("{:^10}", 42); // " 42 " (centered)
// Zero-paddingprintln!("{:05}", 42); // 00042
// Signprintln!("{:+}", 42); // +42println!("{:+}", -42); // -42
// Hexadecimalprintln!("{:x}", 255); // ffprintln!("{:X}", 255); // FFprintln!("{:#x}", 255); // 0xff
// Binaryprintln!("{:b}", 42); // 101010println!("{:#b}", 42); // 0b101010
// Octalprintln!("{:o}", 42); // 52println!("{:#o}", 42); // 0o52Compare to TypeScript:
const pi = 3.14159;
console.log(pi.toFixed(2)); // "3.14"console.log(pi.toPrecision(4)); // "3.142"
const n = 255;console.log(n.toString(16)); // "ff"console.log(n.toString(2)); // "11111111"String Formatting
Section titled “String Formatting”let name = "Alice";
// Truncateprintln!("{:.5}", name); // Alice (already < 5)println!("{:.3}", name); // Ali
// Width and fillprintln!("{:10}", name); // "Alice "println!("{:<10}", name); // "Alice " (left)println!("{:>10}", name); // " Alice" (right)println!("{:^10}", name); // " Alice " (center)println!("{:*<10}", name); // "Alice*****" (custom fill)Escape Sequences
Section titled “Escape Sequences”println!("New line\n");println!("Tab\there");println!("Backslash: \\");println!("Quote: \"");println!("Single quote: \'");println!("Unicode: \u{1F44D}"); //Format! Macro
Section titled “Format! Macro”Create formatted strings without printing:
let name = "Alice";let age = 30;
// Create a Stringlet s = format!("{} is {} years old", name, age);println!("{}", s); // Alice is 30 years old
// Useful for building stringslet filename = format!("report_{}.txt", 2024);Compare to TypeScript:
const name = "Alice";const age = 30;
const s = `${name} is ${age} years old`;console.log(s);Key Differences from TypeScript/JavaScript
Section titled “Key Differences from TypeScript/JavaScript”1. Macros vs Functions
Section titled “1. Macros vs Functions”TypeScript:
console.log("Hello"); // Function callRust:
println!("Hello"); // Macro invocation (note the !)Why macros? They’re expanded at compile time and can check format strings!
2. Format String Syntax
Section titled “2. Format String Syntax”TypeScript:
const name = "Alice";console.log(`Hello, ${name}!`); // Template literalRust:
let name = "Alice";println!("Hello, {}!", name); // Format string3. Debug Printing
Section titled “3. Debug Printing”TypeScript:
const obj = { name: "Alice", age: 30 };console.log(obj); // Pretty print in browser/Node.jsconsole.log(JSON.stringify(obj)); // Manual serializationRust:
let tuple = ("Alice", 30);// println!("{}", tuple); // Errorprintln!("{:?}", tuple); // Debug formatprintln!("{:#?}", tuple); // Pretty debug4. Number Formatting
Section titled “4. Number Formatting”TypeScript:
const n = 42;console.log(n.toString(16)); // "2a" (hex)console.log(n.toString(2)); // "101010" (binary)Rust:
let n = 42;println!("{:x}", n); // 2a (hex)println!("{:b}", n); // 101010 (binary)Common Pitfalls
Section titled “Common Pitfalls”Pitfall 1: Forgetting Braces
Section titled “Pitfall 1: Forgetting Braces”Problem:
let name = "Alice";println!("Hello, name!"); // Prints literally "Hello, name!"Solution:
let name = "Alice";println!("Hello, {}!", name); // "Hello, Alice!"Pitfall 2: Type Doesn’t Implement Display
Section titled “Pitfall 2: Type Doesn’t Implement Display”Problem:
let tuple = (1, 2);println!("{}", tuple); // Error: tuple doesn't implement DisplaySolution:
let tuple = (1, 2);println!("{:?}", tuple); // Use debug formatPitfall 3: Wrong Number of Arguments
Section titled “Pitfall 3: Wrong Number of Arguments”Problem:
println!("{} and {}", 42); // Error: 2 placeholders, 1 argumentSolution:
println!("{} and {}", 42, 100); // Match placeholdersPitfall 4: Trying to Format References
Section titled “Pitfall 4: Trying to Format References”Problem:
let s = String::from("hello");println!("{}", &s); // Works, but...Why it works: Rust automatically dereferences for Display.
Better:
let s = String::from("hello");println!("{}", s); // ClearerBest Practices
Section titled “Best Practices”1. Use Debug for Development
Section titled “1. Use Debug for Development”Implement Display for everything:
struct Point { x: i32, y: i32 }// Lots of boilerplate to implement Display...Use derive Debug:
#[derive(Debug)]struct Point { x: i32, y: i32 }
let p = Point { x: 10, y: 20 };println!("{:?}", p); // Point { x: 10, y: 20 }2. Use Inline Captures for Clarity
Section titled “2. Use Inline Captures for Clarity”Unclear:
println!("User {} (ID: {}) logged in at {}", name, id, time);Clear:
println!("User {name} (ID: {id}) logged in at {time}");Tip: Since Rust 2021, named placeholders capture identifiers from the surrounding scope directly. The older explicit form
println!("{name}", name = name)is exactly whatclippy::uninlined_format_argsflags, with the suggestion to drop the redundantname = nameargument.
3. Use format! for String Building
Section titled “3. Use format! for String Building”Concatenation:
let s = "Hello, ".to_string() + name + "!";Use format!:
let s = format!("Hello, {}!", name);4. Pretty Print Complex Data
Section titled “4. Pretty Print Complex Data”Hard to read:
println!("{:?}", complex_data);Pretty print:
println!("{:#?}", complex_data);Real-World Example
Section titled “Real-World Example”Logging with Formatting
Section titled “Logging with Formatting”TypeScript:
function log(level: string, message: string) { const timestamp = new Date().toISOString(); console.log(`[${timestamp}] ${level}: ${message}`);}
log("INFO", "Server started");log("ERROR", "Connection failed");Rust:
fn log(level: &str, message: &str) { let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S"); println!("[{}] {}: {}", timestamp, level, message);}
fn main() { log("INFO", "Server started"); log("ERROR", "Connection failed");}Displaying Table Data
Section titled “Displaying Table Data”fn print_table(users: &[(&str, u8, f64)]) { println!("{:<15} {:>5} {:>10}", "Name", "Age", "Score"); println!("{:-<32}", ""); // Separator
for (name, age, score) in users { println!("{:<15} {:>5} {:>10.2}", name, age, score); }}
fn main() { let users = [ ("Alice", 30, 95.5), ("Bob", 25, 87.3), ("Charlie", 35, 92.0), ];
print_table(&users);}Output:
Name Age Score--------------------------------Alice 30 95.50Bob 25 87.30Charlie 35 92.00Format Specifiers Reference
Section titled “Format Specifiers Reference”| Specifier | Description | Example | Output |
|---|---|---|---|
{} | Display | println!("{}", 42) | 42 |
{:?} | Debug | println!("{:?}", x) | (1, 2) |
{:#?} | Pretty debug | println!("{:#?}", x) | Multi-line |
{:b} | Binary | println!("{:b}", 42) | 101010 |
{:x} | Lowercase hex | println!("{:x}", 42) | 2a |
{:X} | Uppercase hex | println!("{:X}", 42) | 2A |
{:o} | Octal | println!("{:o}", 42) | 52 |
{:p} | Pointer | println!("{:p}", &x) | 0x7fff… |
{:e} | Lowercase exponential | println!("{:e}", pi) | 3.14159e0 |
{:E} | Uppercase exponential | println!("{:E}", pi) | 3.14159E0 |
{:.N} | Precision (N digits) | println!("{:.2}", pi) | 3.14 |
{:W} | Width (W characters) | println!("{:5}", 42) | ” 42” |
{:<W} | Left align | println!("{:<5}", 42) | ”42 “ |
{:>W} | Right align | println!("{:>5}", 42) | ” 42” |
{:^W} | Center align | println!("{:^5}", 42) | ” 42 “ |
{:0W} | Zero pad | println!("{:05}", 42) | 00042 |
{:+} | Always show sign | println!("{:+}", 42) | +42 |
Further Reading
Section titled “Further Reading”Official Documentation
Section titled “Official Documentation”Exercises
Section titled “Exercises”Exercise 1: Basic Printing
Section titled “Exercise 1: Basic Printing”Print “Hello, Rust!” three times:
fn main() { // Your code here}Solution
fn main() { println!("Hello, Rust!"); println!("Hello, Rust!"); println!("Hello, Rust!");}Exercise 2: Variable Printing
Section titled “Exercise 2: Variable Printing”Print a person’s name and age in format: “Alice is 30 years old”
fn main() { let name = "Alice"; let age = 30; // Your code here}Solution
fn main() { let name = "Alice"; let age = 30; println!("{} is {} years old", name, age);}Exercise 3: Number Formatting
Section titled “Exercise 3: Number Formatting”Format π (3.14159) with 2 decimal places:
fn main() { let pi = 3.14159; // Your code here}Solution
fn main() { let pi = 3.14159; println!("{:.2}", pi); // 3.14}Exercise 4: Debug Printing
Section titled “Exercise 4: Debug Printing”Print a vector using debug format:
fn main() { let numbers = vec![1, 2, 3, 4, 5]; // Your code here}Solution
fn main() { let numbers = vec![1, 2, 3, 4, 5]; println!("{:?}", numbers); // [1, 2, 3, 4, 5]}Exercise 5: Create Formatted String
Section titled “Exercise 5: Create Formatted String”Create a string “User: Alice, Score: 95.5” using format!:
fn main() { let name = "Alice"; let score = 95.5; let s = /* your code */; println!("{}", s);}Solution
fn main() { let name = "Alice"; let score = 95.5; let s = format!("User: {}, Score: {}", name, score); println!("{}", s);}Summary
Section titled “Summary”What you’ve learned:
println!andprint!macros- Format placeholders (
{},{:?}, etc.) - Number formatting (precision, width, padding)
- Debug vs Display formatting
format!macro for string building- Named and positional parameters
Key macros:
println!() // Print with newlineprint!() // Print without newlineeprintln!() // Print to stderrformat!() // Create formatted StringCommon patterns:
println!("{}", x); // Displayprintln!("{:?}", x); // Debugprintln!("{:#?}", x); // Pretty debugprintln!("{:.2}", pi); // Precisionprintln!("{:10}", n); // WidthFormatting is powerful and type-safe in Rust!