Explain the semantics of the built-in copy. Is it safe with overlapping slices?
Question 46MediumGo 1.22 to 1.25
copy(dst, src) copies min(len(dst), len(src)) elements and returns that count. It uses len, not cap. So copying into make([]T, 0, n) copies nothing, which is a common mistake. It works like memmove and handles overlapping ranges correctly. It also has a special form, copy([]byte, string).
dst := make([]int, 0, 10)
n := copy(dst, []int{1, 2, 3})
fmt.Println(n, dst) // 0 [] -- len(dst) is 0!
s := []int{1, 2, 3, 4, 5}
copy(s[1:], s) // overlapping shift right
fmt.Println(s) // [1 1 2 3 4]
b := make([]byte, 3)
copy(b, "hello") // string source allowed
fmt.Println(string(b)) // hel
// Insert at i using copy (the same idea slices.Insert uses for a single element)
func insert[T any](s []T, i int, v T) []T {
var zero T
s = append(s, zero)
copy(s[i+1:], s[i:])
s[i] = v
return s
}
Interviewer angle: copy vs append(dst[:0], src...) vs slices.Clone. For an independent duplicate, slices.Clone(s) is clearest. Note that it keeps nil-ness: Clone(nil) returns nil.
More on Arrays, Slices, Maps & Strings
- Q44What is the full slice expression a[low:high:max], and when would you use it?
- Q45What is the difference between a nil slice and an empty slice? When does it matter?
- Q47How do arrays differ from slices? Can you convert between them?
- Q48What does this print? (range over an array vs a slice)
- Q49How can subslicing cause memory leaks, and how do you fix them?
- Q50How do you delete elements from a slice efficiently, and what changed with slices.Delete in Go 1.22?