CHAPTER 12 · COMPOSITE TYPES

Arrays

A Go array is a fixed-size sequence of elements of the same type. In practice you'll use slices (next chapter) far more often than arrays, but arrays are the foundation slices are built on, and they do have niche uses of their own.

Learning objectives

  • Declare, initialize, and access arrays.
  • Understand that array length is part of its type.
  • Know that arrays are copied on assignment and function calls.
  • Compare arrays with ==.
  • Recognize when slices are the better choice (almost always).

Declaration

Declare an array by specifying its length and element type:

var nums [5]int          // length 5, zero-valued
fmt.Println(nums)         // [0 0 0 0 0]
!
Length is part of the type [3]int and [5]int are different types. You can't assign one to the other, and a function expecting [3]int can't receive a [5]int. This is why arrays feel rigid.

Initialization

// Explicit length
a := [5]int{1, 2, 3, 4, 5}

// Let Go count for you
b := [...]int{10, 20, 30}
fmt.Println(len(b))           // 3

// Index-based init (sparse)
c := [5]int{2: 99, 4: 88}     // [0 0 99 0 88]

Access & modification

a := [3]string{"go", "rust", "python"}
fmt.Println(a[0])             // go
a[1] = "zig"
fmt.Println(a)                // [go zig python]
fmt.Println(len(a))           // 3

Out-of-bounds access panics at runtime.

Copy semantics

Arrays are value types: assignment and function calls copy them in full.

a := [3]int{1, 2, 3}
b := a                 // full copy
b[0] = 99
fmt.Println(a, b)      // [1 2 3] [99 2 3]

This can be expensive for large arrays. Passing [1000000]int to a function means copying a million ints. Use slices or a pointer (*[N]int) for big arrays.

Comparison

Arrays of comparable element types are ==-comparable:

fmt.Println([3]int{1, 2, 3} == [3]int{1, 2, 3})   // true
fmt.Println([3]int{1, 2, 3} == [3]int{1, 2, 4})   // false

This is one thing slices can't do. Slices are not comparable with == (except to nil).

Multi-dimensional

var grid [3][3]int
grid[1][2] = 7
fmt.Println(grid)    // [[0 0 0] [0 0 7] [0 0 0]]

Arrays vs slices (and when to use arrays)

Slices are dynamic, share-by-reference, and can be passed around cheaply. Arrays are fixed and value-typed. Prefer slices unless:

  • The size is small, constant, and compile-time known (e.g. [16]byte for a hash).
  • You want value semantics, meaning automatic copy on assignment.
  • You want == comparison.
  • You're matching a specific binary layout (network protocol, crypto).

Check your understanding

Practice exercises

EXERCISE 1

Reverse an array

Write a function reverse(a [5]int) [5]int that returns a new array with the elements in reverse order. Don't modify the input.

Show solution
func reverse(a [5]int) [5]int {
    var r [5]int
    for i, v := range a {
        r[len(a)-1-i] = v
    }
    return r
}

Further reading

On to slices.