Go
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions and Methods
-
Section 4: Concurrency
-
Section 5: Packages and Tooling
-
Section 6: More Standard Library
-
Section 7: Building Services
-
Section 8: Advanced Go
-
Section 9: Go in the Cloud-Native Ecosystem
-
Section 10: Data Structures and Algorithms in Go
-
Section 11: Testing and Deployment
-
Section 12: Practical Projects
-
Section 13: More Standard Library Practice
-
Section 14: More Practice Projects
-
Section 15: Design Patterns in Go
-
Section 16: Interview Practice
-
Section 17: Package fmt In Depth
-
Section 18: Package strings and strconv
-
Section 19: Package os and io
-
Section 20: Package time
-
Section 21: Package sort and container
-
Section 22: Package encoding
-
Section 23: Package net/http In Depth
-
Section 24: Package context
-
Section 25: Package regexp and bytes
-
Section 26: Package errors In Depth
-
Section 27: Package crypto and hash
-
Section 28: Package flag and log
-
Section 29: Package sync In Depth
-
Section 30: More Practice Exercises
-
Section 31: Go Modules and Workspaces In Depth
-
Section 32: Generics Deep Dive (Go 1.18+)
-
Section 33: Testing Package In Depth
-
Section 34: More Interview and Whiteboard Practice
-
Section 35: Package math and unicode
-
Section 36: Package path and filepath
-
Section 37: Package database/sql
-
Section 38: Package text/template and html/template
-
Section 39: Package archive and compress
-
Section 40: Lower-Level net Package
-
Section 41: Package runtime and reflect
-
Section 42: Package embed and io/fs
-
Section 43: Go Assembly and CGO Basics
-
Section 44: Building CLIs and TUIs
-
Section 45: Go Performance Tuning
-
Section 46: More Real-World Projects
-
Section 47: Go in Production
-
Section 48: Go Design Patterns
-
Section 49: Go Interfaces Deep Dive
-
Section 50: Final Practice and Review
146: The bytes.Buffer Type
Imagine you're a waiter at a busy restaurant. When a table of six people orders, you don't run to the kitchen after every single person says their dish. That would be a waste of your legs and would drive the chef crazy. Instead, you carry a small notepad. You jot down the appetizer, the drinks, and the entrees as they come. Once the whole table is finished, you hand that single piece of paper to the kitchen.
In Go, the bytes.Buffer is that notepad. It's a variable-sized buffer of bytes that lets you accumulate data efficiently before you finally "hand it over" to a file, a network connection, or just convert it into a final string.
The Scratchpad for Your Bytes
If you've been building strings using the + operator, you've probably noticed it's fine for two or three variables. But strings in Go are immutable. Every time you do s = s + " more text", Go actually creates a brand new string in memory and copies the old content into it. If you're doing this in a loop a thousand times, you're creating a thousand temporary strings for the garbage collector to clean up. That's where bytes.Buffer saves you.
package main
import (
"bytes"
"fmt"
)
func main() {
// Here is our "notepad"
var buf bytes.Buffer
buf.WriteString("User Report\n")
buf.WriteString("-----------\n")
buf.WriteString("ID: 42\n")
buf.WriteByte('\n') // You can write single bytes too
buf.WriteString("Status: Active\n")
// When we're done, we convert the whole thing to a string once.
fmt.Print(buf.String())
}
Notice how I didn't have to initialize the buffer with make or a specific size? The buffer handles its own growth. I've found that for most common tasks, letting the buffer manage its own capacity is the way to go, though you can use buf.Grow(n) if you happen to know exactly how big the final result will be.
Playing Nice with io.Writer
One of the biggest reasons I use bytes.Buffer isn't just for strings; it's because it implements the io.Writer interface. In Go, a huge number of standard library functions expect an io.Writer as an argument. This means you can pass a buffer into those functions to "capture" the output in memory instead of sending it straight to the console or a file.
Take fmt.Fprintf, for example. Instead of printing to os.Stdout, you can print directly into your buffer:
var buf bytes.Buffer
fmt.Fprintf(&buf, "The current score is %d to %d", homeScore, awayScore)
// Now the formatted string is sitting in the buffer, ready for whenever you need it.
I personally love this pattern because it separates the logic of formatting your data from the action of sending it somewhere. You build the message in the buffer, and only when it's perfect do you decide whether to log it, send it over HTTP, or save it to a database.
Clearing the Slate
One quick tip: if you're reusing a buffer in a loop, don't forget to clear it. You can use buf.Reset(). This doesn't even necessarily free the memory; it just sets the internal pointer back to the start, allowing the buffer to reuse the same allocated slice for the next batch of data. It's a great way to squeeze a bit more performance out of your code by reducing allocations.
📋 Practical Task
Building a Dynamic CSV Row Generator
You need to create a function that takes a slice of strings and converts them into a single CSV-formatted row (comma-separated). However, there's a catch: you must use a bytes.Buffer to build the string to ensure the solution is memory-efficient, and you must ensure there is no trailing comma at the end of the line.
Requirements:
- Create a function
GenerateCSVRow(fields []string) string. - Use
bytes.Bufferto accumulate the fields. - Separate each field with a comma.
- Return the final result as a string.
- Handle the edge case where the
fieldsslice is empty.
package main
import (
"bytes"
"fmt"
)
func GenerateCSVRow(fields []string) string {
// Your code here
}
func main() {
test1 := []string{"John", "Doe", "Engineer", "New York"}
fmt.Println("Test 1:", GenerateCSVRow(test1))
// Expected: John,Doe,Engineer,New York
test2 := []string{"SingleField"}
fmt.Println("Test 2:", GenerateCSVRow(test2))
// Expected: SingleField
test3 := []string{}
fmt.Println("Test 3:", GenerateCSVRow(test3))
// Expected: (empty string)
}
There are no comments for now.