When Arrays Are the Right Choice
Fast recall
Quick revision
Core answer
[32]byte for aInterview-ready guide
Interview answer
Arrays earn their place in Go when the bound itself carries meaning. The
clearest example comes straight from the standard library: crypto/sha256
computes a digest with Sum256, and its return type is [32]byte — not a
slice. A SHA-256 digest is exactly thirty-two bytes by definition; a length
that could vary would be a different, wrong type. The same logic applies to
[3]uint8 for an RGB pixel or [4][4]float64 for a transformation matrix:
the number is part of what the value is, and the type system should enforce
it. Compile and run this and the type shows the intent:
sum := sha256.Sum256([]byte("interview"))
fmt.Printf("%T\n", sum) // [32]uint8The second reason is value semantics. Because assignment and function calls copy arrays, passing one gives the callee a private copy — the caller's data cannot change. When a small, fixed-size value deserves that protection (a key, a coordinate pair), an array states the intent better than a defensive slice copy.
There is also the literal-count form: auto := [...]int{1, 2, 3, 4} asks
the compiler to count, producing a [4]int. It is still an array — the
length is fixed at compile time — and %T confirms it: [4]int.
For everything else, slices are the default. A collection that grows, a buffer passed between functions, a view over data — those all want shared backing storage, which is what a slice provides. So the rule an interviewer wants to hear: reach for an array when the size is a fact about the data, and for a slice when the size is a variable about the problem.
When Arrays Are the Right Choice
Direct Answer
Use an array when the fixed length is part of the meaning: [32]byte for a
Deep Dive & Architecture
The question "when should I use an array?" is really asking "what does an array guarantee that a slice doesn't?" — and there are exactly two guarantees worth having.
Guarantee one: the type system enforces the bound
When sha256.Sum256 declares that it returns [32]byte, every caller gets
a value whose length the compiler checked. You cannot accidentally pass a
[31]byte digest around, cannot loop past it with a wrong constant without
the compiler noticing the shape mismatch, and cannot store it where a
different-length array is expected. The length has been promoted from a
runtime fact (slice: len(x) varies) to a compile-time fact (array: part
of the type).
Executed proof of the distinction, from the Go compiler itself:
arr := [...]int{1, 2, 3} // [...] counts for you: the type is [3]int
slc := []int{1, 2, 3} // [] is a slice: length lives in the header
fmt.Printf("%T %T\n", arr, slc) // [3]int []int
One extra keystroke — ... versus nothing — is the difference between a
value type carrying its length and a reference-header pointing at storage.
Misreading this literal is one of the most common beginner bugs, which is
why it appears among the traps in the next question.
Guarantee two: copies are isolation
Because y := x copies the elements, an array is a cheap way to make a
function promise not to mutate. For small, fixed data — a key schedule, a
hash, a fixed set of coordinates — the copy cost is trivial and the
protection is exactly what you want. The moment data is large or you want
the function to modify the caller's view, that same copying becomes the
reason to switch to slices.
The honest frequency answer
In real Go codebases, arrays appear mostly in these shapes: fixed-size
protocol fields, crypto and hashing, matrices and numeric kernels, and as
the hidden backing storage that slices are built on. If you cannot name
which of those reasons applies, a slice is almost certainly the right
choice — and being able to say that out loud, with the [32]byte example,
is what turns this from a trivia answer into an engineering answer.
Code Example
sum := sha256.Sum256([]byte("interview"))
fmt.Printf("%T\n", sum) // [32]uint8
rgb := [3]uint8{255, 128, 0}
auto := [...]int{1, 2, 3, 4} // still an array: [4]int
Common Mistakes & Pitfalls
- Using arrays as the default collection and converting to slices later.
- Missing the [...] literal-count form and hand-counting constants.
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.