Rust’s println!: Way More Powerful Than You Think
- Ruud Wijnands
- Dec 8, 2024
- 3 min read
Updated: Oct 26
When I started learning Rust, I treated println! like a simple print statement. You know, “just show some text” and move on. Turns out it’s a lot more than that. It’s basically a mini language for string formatting, and once you actually get what it can do, it’s powerful to use.
If you’ve played with Python’s f-strings or .format(), you’ll recognize the vibe. But Rust adds a layer of precision and safety that’s surprisingly satisfying once it clicks.
Start with the Basics
You’ve seen this one:
Nothing to explain here, just a simple substitution. But what’s hiding underneath is a complete formatting system that can do way more.
Argument Positioning
You can reuse values by their index:
Or use named arguments if you prefer something more readable (and future-proof):
Honestly, once you start using named arguments, it’s hard to go back. They make long-format strings way less painful to read six months later.
Alignment Magic
Now it gets fun. You can align text left, right, or center:
This is helpful when you want your console output to look neat, like printing a small table or aligning values in logs. It’s one of those “little touches” that make your CLI feel better.
Custom Padding Characters
Want to go beyond spaces? You can pick your own padding character:
I don’t use this daily, but now and then I’ll pad things with - or * just to visually separate sections in debug output. It’s a small thing, but it helps.
Precision Control
For floats, .precision controls decimal places:
But here’s the fun part — it also works on strings (yep, for truncation):
I’ve used this trick for quick-and-dirty text truncation in tables. Not the cleanest approach, but when you’re hacking on CLI tools, speed wins.
You can also mix width and precision:
Numbers: The Good Stuff
Formatting numbers is where println! shines. Binary, octal, hex — all built in:
Need zero-padding? Easy:
Perfect for logs, file counters, or pretending you’re building a retro mainframe interface.
Debug Output — Your New Best Friend
This one you’ll use all the time:
That :? flag prints the debug representation of anything that implements Debug.
Structs, enums, tuples, it doesn’t matter; if it’s Debug, it prints.
At this point, I’m not even consciously typing it anymore. It’s just muscle memory.
Making Custom Types Printable
If you want to make your own structs printable, you’ve got two options: Display and Debug.
Display is for nice, human-readable output:
But unless you’re writing user-facing output, you’ll be fine just slapping #[derive(Debug)] on your struct and using {:?}. Life’s too short to handcraft fmt impls for everything.
Combining Everything
Here’s a pattern I use constantly — printing nicely aligned columns:
Or just having fun with formatting:
Okay, you probably won’t need that last one, but it’s neat to know it works.
Quick Cheatsheet
If you’re like me and constantly forget the syntax:
:<, :>, :^ — alignment (left, right, center)
:width — field width
:.precision — decimals or string truncation
:+ — always show sign
:0width — zero-padding
:b, :o, :x — binary, octal, hex
:? — debug output (you’ll overuse this one)
Wrapping Up
The println! formatting system is one of those things that feels excessive at first and then you wonder how you ever lived without it. It turns messy string concatenations into clean, readable output, and Rust’s compiler keeps you honest by catching format errors at compile time. You don’t need to memorize everything. Just start small, experiment, and let the rest fall into place as you go.
Summary Table
Format Specifier | Description |
:< | Left-align the value within the width. |
:> | Right-align the value within the width. |
:^ | Center-align the value within the width. |
:<width> | Specify minimum width. |
:<fill><align> | Specify fill character and alignment. |
:.<precision> | Set precision for floats or limit string length. |
:+ | Always show a sign for numbers. |
: | Show a space for positive numbers. |
:b | Binary format. |
:o | Octal format. |
:x/:X | Hexadecimal (lowercase/uppercase). |
:? | Debug representation. |
:06 | Zero-padded to width 6. |
This flexibility allows println! to handle a wide range of formatting needs!

