初学者来自程序员。我需要复制切片(以及底层数组的一部分),以便调用者不会改变数组的原始元素。我想我可以编写一个函数来为特定类型的数组执行此操作:
func duplicateSliceOfSomeType(sliceOfSomeType []SomeType) []SomeType {
dulicate := make([]SomeType, len(sliceOfSomeType))
copy(duplicate, sliceOfSomeType)
return duplicate
}
但有没有办法一般地创建相同的方法,也许没有泛型?
func duplicateSlice(slice []?) []?{
duplicate := make([]?, len(slice))
copy(duplicate, slice)
return duplicate
}
答案 0 :(得分:26)
您可以编写一个简单的语句来制作切片的浅表副本,
b := append([]T(nil), a...)
相当于,
b := make([]T, len(a))
copy(b, a)
例如,
package main
import "fmt"
type T int
func main() {
a := []T{4, 2}
b := append([]T(nil), a...)
fmt.Println(&a[0], a, &b[0], b)
b[0] = 9
fmt.Println(&a[0], a, &b[0], b)
}
输出:
0x10328000 [4 2] 0x10328020 [4 2]
0x10328000 [4 2] 0x10328020 [9 2]
附录:
Common difficulties with reflection
如果人们不熟悉Go,他们就不应该使用反射。
-rob
即使是专家,反思也很微妙。它暴露了其细节 理解取决于了解如何基本的事情 语言有效,在较小程度上,如何实施。它 即使是经验丰富的Go程序员也会感到困惑;新的 铸造Gophers有更重要,更简单的东西需要学习 第一。那些过早学习反思的人会把自己迷惑起来 他们对那些基本面的理解。最好把它放在手臂上 长度,直到图片的其余部分清晰。
-Rob
那就是说,
package main
import (
"fmt"
"reflect"
)
func CopySlice(s interface{}) interface{} {
t, v := reflect.TypeOf(s), reflect.ValueOf(s)
c := reflect.MakeSlice(t, v.Len(), v.Len())
reflect.Copy(c, v)
return c.Interface()
}
type T int
func main() {
{
// append
a := []T{4, 2}
b := append([]T(nil), a...)
fmt.Println(&a[0], a, &b[0], b)
b[0] = 9
fmt.Println(&a[0], a, &b[0], b)
}
{
// make and copy
a := []T{4, 2}
b := make([]T, len(a))
copy(b, a)
fmt.Println(&a[0], a, &b[0], b)
b[0] = 9
fmt.Println(&a[0], a, &b[0], b)
}
{
// reflection
a := []T{4, 2}
b := CopySlice(a).([]T)
fmt.Println(&a[0], a, &b[0], b)
b[0] = 9
fmt.Println(&a[0], a, &b[0], b)
}
}
输出:
0xc20800a200 [4 2] 0xc20800a210 [4 2]
0xc20800a200 [4 2] 0xc20800a210 [9 2]
0xc20800a290 [4 2] 0xc20800a2a0 [4 2]
0xc20800a290 [4 2] 0xc20800a2a0 [9 2]
0xc20800a310 [4 2] 0xc20800a320 [4 2]
0xc20800a310 [4 2] 0xc20800a320 [9 2]
答案 1 :(得分:0)
您可以使用reflect
包来复制任何类型的副本,具体为reflect.Copy
:http://golang.org/pkg/reflect/#Copy
答案 2 :(得分:0)
随着 Go 1.18(2022 年初发布的候选版本)中引入类型参数,这将很容易实现。
基于 current proposed specs,您可以编写这样的通用函数:
func duplicateSlice[T any](src []T) []T {
dup := make([]T, len(src))
copy(dup, src)
return dup
}
并使用它:
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]
}
您可以在此 Go2 playground 中运行此代码。
答案 3 :(得分:0)
为了完整起见,为了扩展 Evan's answer,以下是在 Go 1.18 之前如何使用 reflect.Copy
完成相同事情的示例:
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
}
请记住,使用 reflect
包将比使用当前 accepted answer 中的方法慢得多。将此处提供的代码视为一个人为的示例以供参考。