Go

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

All 37 Arrays, Slices, Maps & Strings questions