Arrays
An array in Go is a fixed-size sequence of elements of the same type.
Introduction
An array in Go is a fixed-size sequence of elements of the same type. Arrays are values — assigning or passing an array copies all elements. Because of this, arrays are rarely used directly in application code; slices (built on arrays) are the idiomatic collection type.
Understanding arrays is still essential: slices reference underlying arrays, and bugs arise when multiple slices share the same array backing store. Interviewers ask about array vs slice semantics and when fixed size matters (cryptography, embedded systems, stack buffers).
This lesson covers declaration, initialization, array literals, and the relationship between array length (part of type) and slice length (dynamic).
The story
A network appliance firmware stores a fixed-size routing table with exactly 256 entries — arrays have compile-time length, so the Go compiler rejects code that writes past the boundary. When building a CAN bus frame parser for an automotive telemetry pipeline, fixed [8]byte arrays match hardware frame sizes exactly.
Arrays are rarely exposed in APIs (slices are preferred), but they underpin hash tables, ring buffers in Docker's networking stack, and cryptographic fixed-width blocks.
Understanding the topic
Key concepts
- var a [5]int declares array of 5 ints — length is type part: [5]int != [10]int.
- Initialization: zeros by default; a := [3]int{1, 2, 3} or [...]int{1,2,3} for inference.
- Arrays are values — assignment copies entire array.
- len(a) returns array length; no append on arrays.
- Multidimensional: [2][3]int is array of 2 arrays of 3 ints.
- Slices are views into arrays — next lesson covers slices deeply.
Step-by-step explanation
- Declare with fixed size known at compile time.
- Index with a[i]; bounds checked at runtime (panic if out of range).
- Range iterates index and value over array.
- Pass to function copies array — use pointer *[5]int or slice for efficiency.
- Array literal sets elements; missing indices are zero.
- ... inference counts elements: [...]int{1,2,3} becomes [3]int.
Practical code example
Fixed-size buffer and passing array vs pointer:
package mainimport "fmt"func sumArray(arr [5]int) int {total := 0for _, v := range arr {total += v}return total}func fillViaPointer(arr *[5]int, val int) {for i := range arr {arr[i] = val}}func main() {nums := [5]int{10, 20, 30, 40, 50}fmt.Println("sum:", sumArray(nums))var buf [3]bytecopy(buf[:], []byte("Go"))fmt.Printf("buf=%q len=%d\n", buf, len(buf))fillViaPointer(&nums, 0)fmt.Println("after reset:", nums)}
Line-by-line code explanation
var table [256]Routedeclares a fixed-size array — length is part of the type.table[0] = Route{Dest: "10.0.0.0/8"}assigns to an index — bounds checked at runtime.len(table)returns 256 — always equal to the declared size.var frame [8]bytematches an exact wire-format size for binary protocols.copy(dst[:], src)copies bytes between arrays and slices safely.table2 := tablecopies the entire array — assignment is by value, not reference.[...]int{1, 2, 3}lets the compiler infer array length from literals.array passed to func takes [N]T— different lengths are incompatible types.
Key takeaway: Prefer slices for APIs. Use arrays when size is compile-time constant (SHA256 digest is [32]byte).
Real-world use
Where you'll use this in production
- Cryptographic hashes: sha256.Sum returns [32]byte.
- Fixed-width protocol fields in binary encoding.
- Stack-allocated buffers avoiding heap allocation.
- Matrix operations with known dimensions at compile time.
Best practices
- Use slices instead of arrays in function parameters.
- Use [...]T{...} when size inference is convenient.
- Document when fixed size is intentional (security, protocol).
- Pass *[N]T only when mutation needed without slice overhead.
- Be aware of copy cost for large arrays.
Common mistakes
- Using array as function param expecting mutation — copy prevents it.
- Confusing [5]int and [10]int as same type — they're different types.
- Expecting append on arrays — use slices.
- Sharing array via slices unintentionally — mutating slice affects siblings.
- Large arrays on stack — can cause stack overflow in recursion.
Advanced interview questions
Q1BeginnerArray vs slice?
Q2BeginnerIs array size part of type?
Q3IntermediateWhen pass array to function?
Q4IntermediateWhy [32]byte for hash?
Q5AdvancedMultiple slices share array — what happens on append?
Summary
Arrays are fixed-size value types; size is part of the type. Assignment copies all elements — expensive for large arrays. Slices (next lesson) are built on arrays and used everywhere. Use arrays for fixed protocol/crypto sizes; slices for everything else. Next lesson: slices — Go's primary collection type.