Search code examples
gocopyslice

How does the copy function work?


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

Solution

  • The specification 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 documentation 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 two 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 five 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 two elements were copied because the destination only had two 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 two elements were copied, but this time because the source had only two elements.

    So copy() will only copy as many elements as the source or destination has, whichever is smaller. Or in other words, as many as the source "provides" or destination can "accommodate", 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 the 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\n", 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 five 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 four 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 four 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:

    Go Slices: usage and internals

    Arrays, slices (and strings): The mechanics of 'append'