Lesson 2 · Foundations
Types & zero values
There is no uninitialised memory in Go — and that's a design tool.
Your win: declare variables the idiomatic way, and explain what "the zero value" is and why Go programs (and our repo) lean on it to avoid constructors and null checks.
Declarations, quickly
var count int // explicit type, zero value (0)
name := "spike" // short form, type inferred — only inside functions
const maxRetries = 10 // compile-time constant
var ids []string // a nil slice — still usable
Two rules that surprise newcomers: types are static and strict —
there are no implicit numeric conversions, so you must write
float64(count) explicitly; and := only works inside a
function (package-level needs var).
Every type has a zero value
Declare a variable without initialising it and Go gives it a well-defined zero value — never random memory.1
| Type | Zero value |
|---|---|
numbers (int, float64) | 0 |
string | "" (empty, not nil) |
bool | false |
| pointer, slice, map, channel, func, interface, error | nil |
struct | every field set to its own zero value |
"Make the zero value useful" — a proverb with teeth
Go's standard library is designed so the zeroed value already works, so callers
don't need a constructor.2 A
var mu sync.Mutex is ready to Lock(). A nil slice
can be append-ed and range-d. A bytes.Buffer
works from zero.
type EmailRepo struct{} — an empty struct
(spike/.../infrastructure/repositories/email.go:17).
Its zero value is a fully working adapter, so the composition root just writes
&repositories.EmailRepo{} with nothing to configure
(email_modifier_service.go:39). And
type Emails []*Email starts life nil yet
Add() appends to it fine — the zero value at work.
nil map is the exception: you can read it (you get zero
values back), but writing to a nil map panics. Maps must be
make-d before writing. Slices don't have this problem.
Why this matters for interviews
The zero value is the reason Go rarely needs null checks or "is it initialised?" ceremony, and why constructors are optional rather than mandatory. Being able to say that — and name the nil-map exception — signals you actually think in Go, not just write it.
A Tour of Go — "Basics" (variables, zero values, type conversions)
Interactive; type a wrong conversion and watch it fail to compile. Then skim Effective Go's short section on zero values.
→ go.dev/tour — zero values
→ Effective Go — allocation & zero values
Check yourself (from memory)
Q1. An uninitialised Go variable holds…
0, "",
false, or nil depending on type. Never garbage.
Q2. Why can &repositories.EmailRepo{} be used with no configuration?
struct{} whose zero
value already works — "make the zero value useful" applied to our repositories.
Q3. Assigning an int into a float64 variable needs…
float64(n). Strict static typing, caught at compile time.
sync.Mutex, bytes.Buffer,
a nil slice (append/range). In our repo: type EmailRepo struct{} is a
working adapter straight from its zero value, and type Emails []*Email
is nil-then-appendable.iota, typed vs untyped constants, or why string
zero is "" not nil? Ask me.
2. Go Proverbs — "Make the zero value useful"; Effective Go.