ProgrammingGo Developer

How does copy() work in Go when copying slices? What are the features, limitations, and unexpected effects related to the growth of length and capacity of the slice? What happens when slices overlap each other and an attempt is made to copy them with overlapping?

Pass interviews with Hintsage AI assistant

Answer

The copy(dst, src []T) int function copies elements from src to dst.

  • Returns the number of copied elements: min(len(dst), len(src)).
  • The copying is done index-wise: elements src[i] are copied to dst[i].
  • The contents (values) are copied, not pointers to objects.

Nuances and Limitations:

  • If the slices overlap (for example, one is a subarray of the other), the copying is done as if a snippet of the original values is first taken, and then copied (no guarantees of correctness when overlapping).
  • If dst has a shorter length than src, only as much data will be copied as is allowed by the length of dst.
  • If dst has a greater capacity than its length, does copy expand the slice? — No, only len(dst) is considered the target. For expansion, use append beforehand.

Example:

a := []int{1,2,3,4,5} b := make([]int, 3) copy(b, a) // b: [1 2 3]

Overlapping:

x := []int{1,2,3,4} copy(x[1:], x[:3]) // [1 1 2 3]

Trick Question

Can copy() be used to increase the length of a slice? What will happen if a destination slice of greater capacity but smaller length than needed is passed to copy?

Answer:

  • copy() does not change the length of the destination slice — it only copies up to len(dst)
  • If dst has a capacity greater than its length, first expand it via dst = dst[:newLen], then use copy()

Example, often non-obvious:

a := []int{1,2,3} b := make([]int, 0, 5) copy(b, a) // b will remain empty, since len(b) == 0 b = b[:len(a)] copy(b, a) // now b: [1,2,3]

Examples of real mistakes due to ignorance of the nuances of the topic


Story

In the project, data was copied from one slice to another, expecting that copy would automatically expand the length of dst as needed. This did not happen, elements were not copied, resulting in null data coming back in the API response. The error was found only after comparing lengths of slices — the problem was that dst had a large capacity, but its length was 0.


Story

A part of the microservice was working with overlapping slices, mistakenly assuming that copy would always work correctly. As a result, forward copying destroyed the original data, leading to "invisible" bugs when working with buffers. This was resolved by using a temporary buffer (copy(tmp, src), then copy(dst, tmp)).


Story

An engineer optimized the array using copy to sort the data between slices. He expected that copy would adjust the length of dst. It turned out not to be the case, and panics and out-of-bounds access to meaningful data began to appear — they forgot to correctly change the length of the slice before copying.