复制Go切片的通用方法?

Kai*_*ged 8 generics go

初学者来自程序员.我需要复制切片(以及底层数组的一部分),这样调用者就不会改变数组的原始元素.我想我可以编写一个函数来为特定类型的数组执行此操作:

func duplicateSliceOfSomeType(sliceOfSomeType []SomeType) []SomeType {
    dulicate := make([]SomeType, len(sliceOfSomeType))
    copy(duplicate, sliceOfSomeType)
    return duplicate
}
Run Code Online (Sandbox Code Playgroud)

但有没有办法一般地创建相同的方法,也许没有泛型?

func duplicateSlice(slice []?) []?{
    duplicate := make([]?, len(slice))
    copy(duplicate, slice)
    return duplicate
}
Run Code Online (Sandbox Code Playgroud)

pet*_*rSO 26

您可以编写一个简单的语句来制作切片的浅表副本,

b := append([]T(nil), a...)
Run Code Online (Sandbox Code Playgroud)

相当于,

b := make([]T, len(a))
copy(b, a)
Run Code Online (Sandbox Code Playgroud)

例如,

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)
}
Run Code Online (Sandbox Code Playgroud)

输出:

0x10328000 [4 2] 0x10328020 [4 2]
0x10328000 [4 2] 0x10328020 [9 2]
Run Code Online (Sandbox Code Playgroud)

附录:

反思的常见困难

如果人们不熟悉Go,他们就不应该使用反射.

-抢

即使是专家,反思也很微妙.它揭示了细节,这些细节的理解取决于对语言如何工作的基本知识,以及在较小程度上如何实现.即使是经验丰富的Go程序员也会感到困惑; 对于新建的Gophers,首先要学习更重要,更简单的事情.过早学习反思的人会混淆自己对这些基本原理的理解.最好保持手臂的长度,直到图片的其余部分清晰.

-抢

那说,

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)
    }

}
Run Code Online (Sandbox Code Playgroud)

输出:

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]
Run Code Online (Sandbox Code Playgroud)