Introduction: The Question That Haunts Every Go Developer
\nIf you've ever written in Go, you've surely encountered a seemingly simple task: checking whether a string is empty. It seems like it couldn't be simpler, right? But, as shown by the extremely popular question on Stack Overflow (tens of thousands of views!), even such a basic operation has its nuances.
\nIn Go, strings are not just sequences of characters. They are complex data structures, and understanding their internal structure can dramatically affect the performance and readability of your code. In this article, we won't just give you a ready-made answer; we'll look "under the hood" of Go, break down how strings work, and finally figure out which method of checking for emptiness is the best.
\nReady? Let's go! 🚀
\n\nWhat is a String in Go? Peeking Under the Hood
\nBefore talking about checking for emptiness, let's understand what a string actually is in Go. Unlike many other languages, a string in Go is an immutable sequence of bytes. But the most interesting part is how it is stored in memory.
\n\nString Header: The Structure You Don't See
\nInternally, Go represents a string as a small data structure called a string header. In code, it looks like this:
\ntype StringHeader struct {\n Data uintptr // Pointer to the byte array\n Len int // Length of the string in bytes\n}\nThis means that any string, even an empty one, takes up 16 bytes (on a 64-bit system) — 8 bytes for the pointer and 8 bytes for the length. Important: an empty string is not nil! It is a full-fledged object with a pointer (usually to a special empty memory block) and a length equal to zero.
\n\nHow Does This Affect the Check?
\nKnowing this, we can understand how different checking methods work. When you write s == "", the Go compiler does not compare every byte. It does what is called "de facto header comparison". It compares two fields: the length and the pointer. If both fields match, the strings are considered equal. For an empty string, this means comparing Len = 0 and Data = &emptyStringData.
Now let's look at len(s) == 0. The len() function for strings is not a function call; it's a built-in operation. The Go compiler simply reads the Len field from the string header. This is one CPU instruction: MOV (move value).
Three Ways to Check: Myths and Reality
\nOn Stack Overflow, you'll find three main approaches. Let's break down each one from the perspective of performance and style.
\n\n1. len(s) == 0 — The "Classic" Method
\nHow it works: Takes the Len field from the string header and compares it to zero.
Pros:
\n- \n
- Highest performance. This is literally one or two CPU instructions. No function calls, no byte comparisons. \n
- Idiomatic for Go. The Go community loves this method for its simplicity and efficiency. You'll often see it in the standard library. \n
- Clear. "If the length of the string is zero, then the string is empty" — logical and intuitive. \n
Cons: Subjectively, it might seem less readable than s == "" for beginners.
2. s == "" — The "Natural" Method
\nHow it works: Compares two string headers. For an empty string, this compares Len = 0 and Data = &emptyStringData.
Pros:
\n- \n
- Intuitive for beginners. This is what you write in Python, JavaScript, Java. "If the string equals empty