Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a copy of a slice to a function?

Tags:

slice

go

I have a doubt about passing slices to functions.

If I'm not wrong the slices are passed by reference in Go, so if I do something like this:

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    fmt.Println(slice)
    testSlice(slice)
    fmt.Println(slice)
}

func testSlice(slice []int) {
    slice[0] = 5
    slice[4] = 1
}

The testSlice function will actually change the values in the original slice, because it was passed by reference (by default).

There is some easy way that I can directly pass a copy of the slice to the testSlice function?

Sure I can do something like this to create a copy of the slice:

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    fmt.Println(slice)
    testSlice(slice)
    fmt.Println(slice)
}

func testSlice(slice []int) {
    var newSlice []int
    for i := 0; i < len(slice); i++ {
        newSlice = append(newSlice, slice[i])
    }
    newSlice[0] = 5
    newSlice[4] = 1
}

But it needs to go through all values in the original slice to copy each of them, and it doesn't seem to be a great solution.

like image 991
KelvinS Avatar asked Feb 04 '23 14:02

KelvinS


1 Answers

There is a built in function, copy, func copy(dst, src []T) int which is probably what you're looking for. It copies a slice of any type into another slice.

From the docs:

The copy function supports copying between slices of different lengths (it will copy only up to the smaller number of elements). In addition, copy can handle source and destination slices that share the same underlying array, handling overlapping slices correctly.

So

list := []string{"hello", "world"}
newList := make([]string, len(list))
n := copy(newList, list)
// n is the number of values copied

Will copy list into a new slice newList, which share values but not the reference in memory. The int copy returns is the number of values copied.


For an alternative way, from Kostix's comment, you can append the slice to an empty slice. Which is kind of like copying it. It might not be idiomatic, but it allows you to pass the slice into a func as a copy, sort of. If you do this, I recommend copious comments.

thisFuncTakesSliceCopy( append([]string(nil), list...) )

To append a slice to another slice, remember the ellipses (...).

like image 112
Nevermore Avatar answered Feb 19 '23 14:02

Nevermore