Introduction: Why Format a String If You Don't Need to Print It?
Have you ever encountered a situation where you need to neatly assemble a string from multiple parts, insert variables, add indentation, but not output the result to the screen? It seems like all the examples in Go textbooks end with a call to fmt.Println, but what do you do if the string is needed for sending over a network, writing to a file, or passing to another function?
This question plagues thousands of developers, and for good reason — on Stack Overflow it has gathered tens of thousands of views. In this article, we will break down how to format strings in Go without printing, using real code examples. You will learn about the powerful tool fmt.Sprintf, modern approaches with strings.Builder, and the low-level bytes.Buffer. Let's go!
The Problem: Printf Prints, But I Need to Save
Go has a great function fmt.Printf that formats a string and immediately outputs it to the standard output stream. But what if you want to get the formatted string as a value, not as a side effect? For example:
name := "Alice"age := 30// I want to get the string "My name is Alice, I am 30 years old"// but not print it immediatelyBeginner developers often write like this:
fmt.Printf("My name is %s, I am %d years old", name, age)// The string is printed, but we lost it!This works, but the result goes to the console. And we need to save it into a variable for further processing. There is a solution, and it's elegant.
Solution #1: fmt.Sprintf — The King of Formatting
In the fmt package, there is a twin function of Printf called Sprintf. The letter "S" at the beginning stands for "String" — it returns a string, not prints it. This is the most direct and understandable way to format strings in Go without printing.
Basic Example with Sprintf
package main
import ( "fmt")
func main() { name := "Bob" age := 25 score := 98.5
// Format without printing message := fmt.Sprintf("Hello, %s! You are %d years old. Your score: %.1f points.", name, age, score)
// Now message contains the formatted string fmt.Println(message) // Print only now}Output:
Hello, Bob! You are 25 years old. Your score: 98.5 points.Note: Sprintf uses the same placeholders ( %s, %d, %f ) as Printf. The only difference is that the result is returned, not output.
Advanced Placeholders
You can use all of Go's formatting capabilities:
package main
import "fmt"
func main() { // Width alignment leftAligned := fmt.Sprintf("%-10s %d", "Product", 10) rightAligned := fmt.Sprintf("%10s %d", "Product", 10)
// Number formatting price := 1234.5678 formattedPrice := fmt.Sprintf("Price: $%.2f (with VAT: $%.2f)", price, price*1.2)
// Hexadecimal output hexValue := fmt.Sprintf("Hex: %x, Dec: %d", 255, 255)
fmt.Println(leftAligned) fmt.Println(rightAligned) fmt.Println(formattedPrice) fmt.Println(hexValue)}Output:
Product 10 Product 10Price: $1234.57 (with VAT: $1481.48)Hex: ff, Dec: 255fmt.Sprintf is your universal tool for Go string formatting. It works fast, is understandable, and covers 90% of tasks.
Solution #2: strings.Builder — For Complex Constructions
What if you need to assemble a string from many parts, adding them one by one? For example, generating HTML, JSON, or SQL queries. Using Sprintf for each part is inefficient — you will be co