Module lessons (2/5)
Slices: the idiomatic structure
A slice is the most-used data structure in Go: a dynamic view
over an underlying array. Syntax: []T. Unlike arrays, the length is
not part of the type, and you can grow it with append.
Anatomy of a slice
Internally a slice is a three-field structure:
- a pointer to the first element in the underlying array
- a length (
len): number of visible elements - a capacity (
cap): elements available from the start of the view to the end of the underlying array
s := []int{10, 20, 30}
fmt.Println(len(s), cap(s)) // 3 3Creation
a := []int{1, 2, 3} // literal
b := make([]int, 3) // [0 0 0] len=3 cap=3
c := make([]int, 3, 10) // len=3 cap=10 (reserved)
var d []int // nil slice: len=0 cap=0, still usable with appendappend: always assign the result
append adds elements and returns a new slice (potentially
allocating a new array if the capacity is insufficient):
s := []int{1, 2, 3}
s = append(s, 4) // [1 2 3 4]
s = append(s, 5, 6, 7) // append multiple elements
s = append(s, altra...) // concatenate another slice (spread)Slice expression s[a:b]
Extracts a sub-slice from a (inclusive) to b (exclusive):
s := []int{10, 20, 30, 40, 50}
sub := s[1:4] // [20 30 40]
inizio := s[:2] // [10 20]
fine := s[3:] // [40 50]
intera := s[:] // [10 20 30 40 50]Sub-slices share the underlying array with the original slice:
mutations through sub[i] = ... are visible in s as well.
Pitfall: array sharing
s := []int{1, 2, 3, 4}
sub := s[0:2]
sub[0] = 99
fmt.Println(s) // [99 2 3 4] — modified!To get an independent copy, use copy or append:
out := make([]int, len(sub))
copy(out, sub)Try it
Create a slice s with [1, 2, 3] and use append to add 4.
Show hint
ALWAYS assign the result of append back to `s`.
Solution available after 3 attempts
Use a slice expression to extract elements from index 1 inclusive to 3 exclusive (i.e. [20, 30]).
Show hint
Syntax: `s[start:end]`, `start` inclusive, `end` exclusive.
Solution available after 3 attempts
Which of these is WRONG to write?
s := []int{1, 2, 3}
// (a) s = append(s, 4)
// (b) append(s, 4)Recap
[]T: dynamic view over an array; triple (ptr, len, cap).make([]T, len, cap)to pre-allocate;var s []Tfor a usable nil slice.s = append(s, ...): ALWAYS assign the result.s[a:b]shares the underlying array:copy(...)for independent copies.- A
nilslice = OK to read/range/append; quite different from a nil map.