Go by Example: Zero Values
In Go, variables declared without an initial value are given their "zero value". This example explains what these values are for different types and demonstrates the "Make the zero value useful" proverb with structs like sync.Mutex.
Code
package main
import (
"bytes"
"fmt"
"sync"
)
func main() {
// 1. Basic Types
// Variables declared without initialization get a default "zero value".
var i int
var f float64
var b bool
var s string
// Prints: 0, 0, false, "" (empty string)
fmt.Printf("int: %d, float: %f, bool: %t, string: %q\n", i, f, b, s)
// 2. Pointers and Reference Types
// The zero value is 'nil' for pointers, slices, maps, channels, interfaces, and functions.
var ptr *int
var slc []int
var mp map[string]int
fmt.Println("pointer is nil:", ptr == nil)
fmt.Println("slice is nil:", slc == nil)
fmt.Println("map is nil:", mp == nil)
// 3. "Make the zero value useful"
// Many Go types are designed to be used without explicit initialization.
// Example A: sync.Mutex
// A zero-value Mutex is an unlocked mutex. You don't need "NewMutex()".
var mu sync.Mutex
mu.Lock()
fmt.Println("Mutex locked successfully")
mu.Unlock()
// Example B: bytes.Buffer
// A zero-value Buffer is an empty buffer ready to write to.
var buf bytes.Buffer
buf.WriteString("Hello, Zero Value!")
fmt.Println(buf.String())
// Example C: Slices
// A nil slice is functionally equivalent to an empty slice for most operations.
// You can append to it without 'make'.
var names []string
names = append(names, "Alice")
fmt.Println("Appended to nil slice:", names)
}
Explanation
In many languages, uninitialized variables contain random garbage data, leading to unpredictable bugs. Go solves this by guaranteeing that every variable declared without an explicit value is initialized to its zero value. This provides safety and determinism.
The zero values are: 0 for numeric types, false for booleans, "" (empty string) for strings, and nil for pointers, slices, maps, channels, functions, and interfaces. For structs, the zero value is a struct where every field is set to its respective zero value.
A famous Go proverb is "Make the zero value useful." This means designing your types so that they can be used immediately after declaration, without needing a constructor or initialization method. The standard library is full of examples: sync.Mutex is ready to lock, bytes.Buffer is ready to write, and a nil slice is ready to be appended to.
- Safety: No uninitialized memory access.
- Convenience: Reduces boilerplate (no need for
Init()calls). - Nil Slices: Can be used with
append,len, andcapsafely. - Nil Maps: CAUTION: You can read from a nil map, but writing to it causes a panic.

