Skip to content
Theory · Arrays and slices · lesson 1 of 10

Arrays

What you'll learn

What you'll learn:

  • store several values in an array and go over it in a loop;
  • work with slices: create them with make and add elements with append;
  • tell a slice's length from its capacity, and see when two slices share one array;
  • write functions that take a variable number of arguments.
A row of four lockers numbered 0 1 2 3, locker 1 open with a tag a[1] on its door

Picture a row of numbered lockers in a changing room:

  • the lockers are identical and stand side by side;
  • each has a number on its door, and to put something away, you name the number rather than invent a name for the locker;
  • the row is bolted to the floor: as many lockers as were installed, that many there will be.

Five grades can be kept in five variables, but then a sum lists five names, and a loop cannot go over them. For several values of one type, Go has the array—a row of elements of a fixed length. Each element is read and changed by its number, called the index:

GO
package main

import "fmt"

func main() {
    a := [3]int{10, 20, 30}
    fmt.Println(a[0], a[2]) // 10 30
    a[1] = 25
    fmt.Println(a, len(a)) // [10 25 30] 3
}

Let's walk through the example line by line:

  1. a := [3]int{10, 20, 30} sets up a row of three lockers and puts three numbers in them.
  2. a[0] and a[2] read the first and the last locker, so the line prints 10 30.
  3. a[1] = 25 changes what the middle locker holds.
  4. The last Println prints the whole array and its length: [10 25 30] 3.

Notation and indexes

[3]int reads as "an array of three ints". It has two parts:

  • [3] is the length, the number of elements;
  • int is the type of each element.

Indexes start at zero, so three elements have the indexes 0, 1 and 2. The len function returns the array's length, and fmt.Println prints the whole array in square brackets.

Going over it in a loop

An index can be a variable, so a loop can go over an array. Here range len(scores) goes through the indexes from 0 to 4:

GO
scores := [5]int{4, 5, 3, 5, 4}
sum := 0
for i := range len(scores) {
    sum += scores[i]
}
fmt.Println(sum) // 21

On each iteration scores[i] reads the next grade and adds it to sum. After five iterations the program prints the sum 21.

Creating an array

An array can be made in three ways.

A literal with every element

[3]int{10, 20, 30} lists the values in curly braces in order: the first goes to index 0, the second to 1. You create an array this way when all the values are known while writing the code. An extra element beyond the length does not compile.

A var declaration

An array declared with var and no values is filled with zero values: var b [4]int holds [0 0 0 0]. This is handy for an array that will be filled later, for example in a loop.

A partial literal

A literal may list only some of the elements: the rest get the zero value. So [5]int{1, 2} holds [1 2 0 0 0]. The first indexes are filled in order, and the tail stays zeros.

Length is part of the type

The length is part of the type, so [3]int and [4]int are different types. Two limits follow from this:

  • an array [3]int cannot be assigned to a variable of type [4]int: cannot use a (variable of type [3]int) as [4]int value in assignment;
  • the length cannot change after creation either—the row is bolted to the floor.

That is why an array suits collections whose size never changes: the three coordinates of a point, the seven days of the week.

The whole array is copied

A variable of an array type holds all its elements, the way a variable of type int holds a number. So an array is copied in two places.

On assignment

The assignment b := a creates a new array and copies all the elements of a into it. After that each variable has its own elements, and a write to one array is not visible in the other:

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

This is where the locker analogy ends. In real life nobody builds a second row of lockers to give a friend a key. In Go, array assignment does exactly that: a second row appears with copies of everything inside. So b[0] = 9 changes only the second row, and the program prints [1 2 3] [9 2 3].

On a function call

A parameter of type [3]int gets a copy of the array, the way a parameter of type int gets a copy of a number. A function that changes the elements of its parameter leaves the caller's array untouched. The longer the array, the more values each assignment and each call copies.

Interviewers often check this fact with a puzzle: an array was assigned to another variable and the copy was changed—what does the program print? Remember that the array is copied whole, and the original stays as it was.

Common mistake

The array length is taken from a variable:

GO
n := 3
var a [n]int // ✗
TEXT
invalid array length n

The array length must be known to the compiler: it is a literal or a constant, such as const n = 3. A variable's value appears only while the program runs, so it cannot serve as an array length.

Key points

  • An array is a row of elements of a fixed length; indexes go from 0 to len(a) - 1.
  • The length is part of the type: [3]int and [4]int are different types, and the length is a literal or a constant.
  • Assignment and passing to a function copy the whole array.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way