I don't understand how the copy
function works based on the documentation:
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).
func copy(dst, src []Type) int
The spec also covers the builtin functions append()
and copy()
: Appending to and copying slices. You should read it, it's quite clear.
Let's analyze the doc of the builtin copy()
function and its uses with simple examples. You can try all the examples on the Go Playground.
Signature:
func copy(dst, src []Type) int
copy()
is a function, it has 2 parameters, a destination and a source slice, whose element type is the same. It returns a number of type int
which is the number of elements actually copied.
The copy built-in function copies elements from a source slice into a destination slice.
copy()
will copy elements from the src
slice into the dst
slice.
src := []int{10, 11, 12, 13, 14}
dst := []int{0, 1, 2, 3, 4}
n := copy(dst, src)
fmt.Println("n =", n, "src =", src, "dst =", dst)
Output:
n = 5 src = [10 11 12 13 14] dst = [10 11 12 13 14]
It copied all 5 elements, and after the copy the destination has the same elements as the source.
Let's continue the example:
dst = []int{0, 1}
n = copy(dst, src)
fmt.Println("n =", n, "src =", src, "dst =", dst)
Output:
n = 2 src = [10 11 12 13 14] dst = [10 11]
Only 2 elements were copied because the destination only had 2 elements.
Continuing:
src = []int{10, 11}
dst = []int{0, 1, 2, 3, 4}
n = copy(dst, src)
fmt.Println("n =", n, "src =", src, "dst =", dst)
Output:
n = 2 src = [10 11] dst = [10 11 2 3 4]
Again, only 2 elements were copied but this time because the source had only 2 elements.
So copy()
will only copy as many elements as source or destination has, whichever is smaller. Or in other words, as many as the source "provides" or destination can "accomodate", whichever is smaller.
(As a special case, it also will copy bytes from a string to a slice of bytes.)
This means that the source can also be a string
if destination is a []byte
:
str := "Hello World!"
data := make([]byte, 5)
n = copy(data, str)
fmt.Println("n =", n, "str =", str, "data =", data)
fmt.Printf("data as string: %s
", data)
Output:
n = 5 str = Hello World! data = [72 101 108 108 111]
data as string: Hello
This time the source was a string
and copy()
copied 5 bytes of the UTF-8 representation of the string
(this is how Go stores strings in memory).
The source and destination may overlap.
This means that copy()
works correctly even if the destination is a slice which shares the same underlying array as the source slice, and the part of the array designated by source and destination has common parts (overlap).
For example:
copy(src, src[1:])
fmt.Println("n =", n, "src =", src)
Output:
n = 4 src = [1 2 3 4 4]
Here I specified src[1:]
as the source, which is the source without the first element (this is a reslicing). Since I excluded the first element, the source of copy()
has 4 elements, so 4
elements were copied. The result is that elements were "shifted" to a 1-less index (therefore the first element being 0
is now gone from the slice), and the last element was not touched (because only 4 elements were copied).
Copy returns the number of elements copied, which will be the minimum of len(src) and len(dst).
We've seen this in the above examples.
If you need to learn more about slices:
Here is a basic example of how to use the builtin copy function:
// The source slice
source := []int{1, 2, 3,}
// The destination slice is where things will be copied to
destination := make([]int, len(source))
// The copy function returns a count of how many elements are copied from the source slice to the destination slice
copies := copy(destination, source)
// Some printing
fmt.Printf("copied %d elements
", copies) // Outputs: copied 3 elements
fmt.Println("destination slice:", destination) // Outputs: destination slice: [1 2 3]
If the destination
slice is of length n
, and the source
slice is of length m
, and n
< m
the destination slice will be filled with the first n
elements of the source
slice:
source := []int{1, 2, 3,}
destination := make([]int, 1) // <-- Notice the 1
copies := copy(destination, source)
fmt.Printf("copied %d elements
", copies) // Outputs: copied 1 elements
fmt.Println("destination slice:", destination) // Outputs: destination slice: [1]
A gotcha is that if you declare you destination slice as a slice literal like this:
destination := []int{}
The length will be 0 and nothing will be copied in.