The len function
To find out how many elements a slice holds, pass it to the built-in function len:
ourArray := []int{50, 40, 30}
fmt.Println(len(ourArray))
3
len is a built-in function, not a method. You write len(ourArray), never ourArray.len() or ourArray.length. It returns an int, so you can store it, compare it and use it in arithmetic like any other integer. Go also uses len for strings, maps, channels and arrays. For a string it counts bytes, not characters.
The length changes with the slice
Because a slice can grow and shrink, its length is not fixed. Each time you ask, you get the current number of elements:
ourArray = ourArray[:len(ourArray)-1]
fmt.Println(len(ourArray))
ourArray = append(ourArray, 7, 8)
fmt.Println(len(ourArray), ourArray)
2
4 [50 40 7 8]
Re-slicing to [:len(ourArray)-1] removes the last element, so the length drops from 3 to 2. Appending two values then raises it to 4. Remember to assign the result back to the variable: the length belongs to the new slice value, not to the old one.
A slice that is empty, including one declared with var s []int that was never filled, has length 0. Calling len on it is always safe.
Reaching the end of a slice
The valid indices of a slice with length n run from 0 to n - 1. So the last element is at index len(s) - 1, and the one before it is at len(s) - 2. Many languages let you write s[-1] for the last element. Go does not, so the length is how you reach the end:
ages := []int{14, 32, 50, 21}
size := len(ages)
fmt.Println(ages[size-1])
fmt.Println(ages[size-2])
21
50
Storing the length in a variable such as size is optional. Writing ages[len(ages)-1] directly is just as common and avoids an extra name. Either way, the length is read at the moment the line runs, so it always matches the slice as it is then.
The exercise
You work with two slices:
fruits := []string{"mango", "kiwi", "grapefruit"}
ages := []int{14, 32, 50, 21}
- Print the number of fruits with
len(fruits). It is 3. - Print the last age. The slice has four numbers, so the last is at index
len(ages) - 1, which is 3. - Print the second to last age at index
len(ages) - 2, which is 2.
fmt.Println(len(fruits))
fmt.Println(ages[len(ages) - 1])
fmt.Println(ages[len(ages) - 2])
3
21
50
Length and capacity
A slice also has a capacity, which cap reports. It is the number of elements the underlying array can hold from the start of the slice, so it is never smaller than the length. For a literal the two start out equal. After removing the last element by re-slicing, the length is 2 while the capacity stays 3, because the underlying array is untouched:
s := []int{50, 40, 30}
fmt.Println(len(s), cap(s))
s = s[:len(s)-1]
fmt.Println(len(s), cap(s))
3 3
2 3
For the exercises you only need len. Capacity matters later, when you care about how often append has to copy data.
Looping with the length
In Go, for is the only loop keyword. Using len in the condition means the loop stays correct when the slice's size changes.
The length is also the natural limit of a counting loop. This one walks the slice from the end to the start:
for i := len(ages) - 1; i >= 0; i-- {
fmt.Print(ages[i], " ")
}
21 50 32 14
Common mistakes
- Using the length as the last index.
ages[len(ages)]is one past the end and panics at run time. - Taking the last element of an empty slice. With length 0, the index
len(s) - 1is -1, and the program panics withindex out of range [-1]. Testlen(s) > 0first when a slice may be empty. - Calling it like a method.
ages.len()does not exist; writelen(ages). - Confusing length and capacity.
lencounts the elements in the slice.capreports how many fit in the underlying array beforeappendmust allocate a bigger one.
Key takeaways
len(s)is the number of elements, and it changes as the slice grows or shrinks.- The last element is
s[len(s)-1]; Go has no negative indices. - Check for an empty slice before reading from the end.