'Generic way to duplicate slices
I have a need to duplicate slices (and part of the underlying array) so a caller won't mutate the original elements of an array. I think I can write a function to do this for arrays of specific types:
func duplicateSliceOfSomeType(sliceOfSomeType []SomeType) []SomeType {
dulicate := make([]SomeType, len(sliceOfSomeType))
copy(duplicate, sliceOfSomeType)
return duplicate
}
But is there a way to create the same method generically, perhaps without generics?
func duplicateSlice(slice []?) []?{
duplicate := make([]?, len(slice))
copy(duplicate, slice)
return duplicate
}
Solution 1:[1]
Go 1.18
With the introduction of type parameters in Go 1.18 (currently in beta) this will be trivial to accomplish.
Based on the current proposed specs you can write a generic function like this:
func duplicateSlice[T any](src []T) []T {
dup := make([]T, len(src))
copy(dup, src)
return dup
}
And use it as such:
package main
import (
"fmt"
)
func duplicateSlice[T any](src []T) []T {
dup := make([]T, len(src))
copy(dup, src)
return dup
}
func main() {
a := []string{"foo", "bar"}
a2 := duplicateSlice(a)
a[0] = "baz"
fmt.Println(a) // [baz bar]
fmt.Println(a2) // [foo bar]
b := []uint64{8, 12, 30}
b2 := duplicateSlice(b)
b[0] = 7
fmt.Println(b) // [7 12 30]
fmt.Println(b2) // [8 12 30]
}
You can run this code in this GoTip playground.
Experimental slices package
The package golang.org/x/exp/slices provides generic functions for slices. It will probably be moved into the standard lib in Go 1.19.
We can use slices.Clone to accomplish the same as with the previous duplicateSlice function:
package main
import (
"fmt"
"golang.org/x/exp/slices"
)
func main() {
a := []string{"foo", "bar"}
a2 := slices.Clone(a)
fmt.Println(a2) // [foo bar]
}
GoTip playground: https://gotipplay.golang.org/p/-W3_I0eYLdF
Reflection, pre-Go 1.18
For completeness, to expand on Evan's answer, here's an example of how to use reflect.Copy to accomplish the same thing before Go 1.18:
package main
import (
"fmt"
"reflect"
)
func main() {
src := []int{1,2,3}
target := duplicateSlice(src)
src[0] = 9
fmt.Println(src) // [9 2 3]
fmt.Println(target) // [1 2 3]
}
func duplicateSlice(src interface{}) interface{} {
t := reflect.TypeOf(src)
if t.Kind() != reflect.Slice {
panic("not a slice!")
}
v := reflect.ValueOf(src)
target := reflect.MakeSlice(t, v.Cap(), v.Len())
reflect.Copy(target, v)
return target.Interface()
}
Keep in mind that using the reflect package will be much slower than using the approach in the currently accepted answer. Consider the code presented here as just a contrived example for reference.
Link to playground: https://play.golang.org/p/vZ1aQOFTLmU
Solution 2:[2]
You can do a copy on any type by using the reflect package, specifically reflect.Copy: http://golang.org/pkg/reflect/#Copy
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Evan |
