copy


The definition of built-in copy function is here:

func copy(dst, src []Type) int

The copy built-in function copies elements from a source slice into a destination slice. (As a special case, it also will copy bytes from a string to a slice of bytes.) The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum of len(src) and len(dst).

Let’s see a basic example in which source and destination slices aren’t overlapped:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. d := make([]int, 3, 5)
  7. s := []int{2, 2}
  8. fmt.Println("Before copying (destination slice): ", d)
  9. fmt.Println("Copy length is: ", copy(d, s))
  10. fmt.Println("After copying (destination slice): ", d)
  11. d = make([]int, 3, 5)
  12. s = []int{2, 2, 2}
  13. fmt.Println("Before copying (destination slice): ", d)
  14. fmt.Println("Copy length is: ", copy(d, s))
  15. fmt.Println("After copying (destination slice): ", d)
  16. d = make([]int, 3, 5)
  17. s = []int{2, 2, 2, 2}
  18. fmt.Println("Before copying (destination slice): ", d)
  19. fmt.Println("Copy length is: ", copy(d, s))
  20. fmt.Println("After copying (destination slice): ", d)
  21. }

In the above example, the destination slice’s length is 3, and the source slice’s length can be 2, 3, 4. Check the result:

  1. Before copying (destination slice): [0 0 0]
  2. Copy length is: 2
  3. After copying (destination slice): [2 2 0]
  4. Before copying (destination slice): [0 0 0]
  5. Copy length is: 3
  6. After copying (destination slice): [2 2 2]
  7. Before copying (destination slice): [0 0 0]
  8. Copy length is: 3
  9. After copying (destination slice): [2 2 2]

We can make sure the number of copied elements is indeed the minimum length of source and destination slices.

Let’s check the overlapped case:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. d := []int{1, 2, 3}
  7. s := d[1:]
  8. fmt.Println("Before copying: ", "source is: ", s, "destination is: ", d)
  9. fmt.Println(copy(d, s))
  10. fmt.Println("After copying: ", "source is: ", s, "destination is: ", d)
  11. s = []int{1, 2, 3}
  12. d = s[1:]
  13. fmt.Println("Before copying: ", "source is: ", s, "destination is: ", d)
  14. fmt.Println(copy(d, s))
  15. fmt.Println("After copying: ", "source is: ", s, "destination is: ", d)
  16. }

The result is like this:

  1. Before copying: source is: [2 3] destination is: [1 2 3]
  2. 2
  3. After copying: source is: [3 3] destination is: [2 3 3]
  4. Before copying: source is: [1 2 3] destination is: [2 3]
  5. 2
  6. After copying: source is: [1 1 2] destination is: [1 2]

Through the output, we can see no matter the source slice is ahead of destination or not, the result is always as expected. You can think the implementation is like this: the data from source slice are copied to a temporary place first, then the elements are copied from temporary to destination slice.

copy requires the source and destination slices are the same type, and an exception is the source is string while the destination is []byte:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. d := make([]byte, 20, 30)
  7. fmt.Println(copy(d, "Hello, 中国"))
  8. fmt.Println(string(d))
  9. }

The output is:

  1. 13
  2. Hello, 中国

Reference:
copy() behavior when overlapping.