Deleting from a slice in place: what do both lines print?
s := []int{1, 2, 3, 4, 5}
t := append(s[:1], s[3:]...)
fmt.Println(t, s)
u := []int{1, 2, 3, 4, 5}
v := slices.Delete(u, 1, 3)
fmt.Println(v, u)
Output:
[1 4 5] [1 4 5 4 5]
[1 4 5] [1 4 5 0 0]
s[:1] has length 1 but capacity 5, so append writes 4 and 5 into indices 1 and 2 of the same array. t looks right, but s (and every other slice that shares that array) now holds [1 4 5 4 5]. The stale tail values are still there.
slices.Delete does the same shift, but since Go 1.22 it also zeroes the elements between the new length and the old length. That is why u ends in 0 0. The zeroing lets the garbage collector free pointers held in the dropped tail (for example in a []*Conn), and it makes stale aliases easy to spot. slices.Compact, slices.DeleteFunc, and slices.Replace clear the tail in the same way.
Code-review rule: after an in-place delete, use only the returned slice (s = slices.Delete(s, i, j)) and treat every older header over the same array as invalid. If callers must keep the original, clone it first.
More on Tricky Output & Code-Review Puzzles
- Q510Go 1.23 range-over-func: what does this buggy iterator do?
- Q511What does this counter print, and how do you prove the bug?
- Q513Embedding is not inheritance: what does this print, and which line does not compile?
- Q514Type switch puzzle: what does describe return for each input?
- Q515Package initialization order: what does this program print?