What is an ArraySlice, and why does slice[0] crash?
Predict first
What does this print?
let a = [10, 20, 30, 40, 50]
let s = a[2...]
print(s.startIndex, s[2], s.first!)
- 0 30 30
- 2 30 30
- 2 20 30
Predict first
What happens?
let a = [10, 20, 30, 40, 50]
let s = a[2...]
print(s[0])
- Prints 10
- Prints 30
- Crashes
Mental model. A slice is a window cut into a long wall. The bricks keep their original numbers, and the wall stays standing.
A slice is a view into its parent array. Creating one is O(1) because it shares the parent’s buffer, and it keeps the whole parent alive for as long as the slice lives.
Crucially, a slice keeps the parent’s indices. a[2...] starts at index 2, so s[0] is out of range and traps. Use s.startIndex or s.first. Array(s) makes an independent array that starts at 0 and releases the parent. Data and Substring follow the same rule.
The slice starts at index 2 and still addresses the same elements, so s[2] is 30.
Index 0 is outside the slice’s range (2..<5), so it is an out-of-bounds trap.
Common traps
- Indexing a slice from 0. Works by luck on
prefixslices and crashes ondropFirstones. - Keeping a small slice of a huge array. The whole buffer stays in memory. Copy it with
Array(slice)if you keep it long.
They might follow up with
- Which methods return slices?
dropFirst,prefix,suffix, and range subscripts. - Is a slice a value type? Yes. Mutating a slice triggers copy-on-write like any array.
Related questions
- 1.1.7 What is copy-on-write? Which types use it?
- 2.3.5 What is Data, and how do you convert it to and from text?
- 2.1.11 How do you write your own Collection, and what do you get for free?
← What happens if you mutate an array while you loop over it? map, filter, compactMap, flatMap, reduce, forEach: when do you use… →