Output and Formatting
Learn how to print output in Rust using the println! macro and its rich 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 expressive 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 expressive and type-safe in Rust!