制作结构副本

可以使用赋值简单地复制结构。

type T struct {
    I int
    S string
}

// initialize a struct
t := T{1, "one"}

// make struct copy
u := t // u has its field values equal to t

if u == t { // true
    fmt.Println("u and t are equal") // Prints: "u and t are equal"
}

在上面的例子中,'t'和’u’现在是单独的对象(结构值)。

由于 T 不包含任何引用类型(切片,地图,通道)作为其字段,因此可以修改上面的 tu 而不会相互影响。

fmt.Printf("t.I = %d, u.I = %d\n", t.I, u.I) // t.I = 100, u.I = 1

但是,如果 T 包含引用类型,例如:

type T struct {
    I  int
    S  string
    xs []int // a slice is a reference type
}

然后,通过赋值的简单副本将切片类型字段的值也复制到新对象。这将导致两个不同的对象引用相同的切片对象。

// initialize a struct
t := T{I: 1, S: "one", xs: []int{1, 2, 3}}

// make struct copy
u := t // u has its field values equal to t

由于 u 和 t 都通过其字段 xs 引用相同的切片,因此更新一个对象的切片中的值将反映另一个对象的更改。

// update a slice field in u
u.xs[1] = 500

fmt.Printf("t.xs = %d, u.xs = %d\n", t.xs, u.xs)
// t.xs = [1 500 3], u.xs = [1 500 3]

因此,必须格外小心以确保此引用类型属性不会产生意外行为。

例如,要复制上述对象,可以执行切片字段的显式副本:

// explicitly initialize u's slice field
u.xs = make([]int, len(t.xs))
// copy the slice values over from t
copy(u.xs, t.xs)

// updating slice value in u will not affect t
u.xs[1] = 500

fmt.Printf("t.xs = %d, u.xs = %d\n", t.xs, u.xs)
// t.xs = [1 2 3], u.xs = [1 500 3]