# 复制结构体(创建一份拷贝)

结构体的复制用赋值语句这种简单的形式。

{% tabs %}
{% tab title="Go" %}

```go
package main

import "fmt"

type T struct {
	I int
	S string
}

func main() {
	// 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"
		fmt.Printf("u address is: %p\nt address is:%p\n", &u, &t)
	}
}
```

{% endtab %}

{% tab title="Output" %}

```
u and t are equal
u address is: 0xc00000c0c0
t address is:0xc00000c0a0
```

{% endtab %}
{% endtabs %}

:point\_right: [点击此处](https://play.golang.org/p/gcJ3c-BQjET) :point\_left: 亲自在编程操场测试上述代码。

上例中，`t` 和 `u` 就是独立的对象(结构体)了。

因为类型`T`中不包含任何引用类型(切片slice、映射map、数据通道channel)作为它的字段，因此对`t`和`u`的值进行修改并不会彼此影响。

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

**然而**，假如`T`中包含的有引用类型，比如：

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

如果还只是简单地用赋值语句来拷贝对象，其结果是两个不同的对象引用了相同的切片。

```go
// 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`都指向了相同的切片，因此在一个变量中修改了切片，另一个变量也会受影响而改变。

```go
// 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]
```

因此，**在复制包含引用类型的结构体时需要十分小心**，记住这个特性，否则可能会出现意料不到的错误。

如果要结构体中引用类型字段也真实拷贝独立存在，修改其中一个而不影响另一个，需要像下面这样显式地完成复制：

```go
// 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]
```

{% hint style="info" %}

#### 译者注

本节谈论的利用赋值语句隐式拷贝和make函数显式拷贝的区别，实际上就是浅拷贝和深拷贝的区别。

在用赋值语句拷贝时，系统虽然为`u.xs`分配了新内存地址用于存放值，此地址与`t.xs`不同，但所存放的值并不是具体的切片`[1 2 3]`，而是原切片的指针。在赋值语句发生拷贝的瞬间，复制了指针，而不是复制了值，所以指向了相同的内存空间。
{% endhint %}

![赋值语句拷贝示意图，xs字段直接存放的是切片的指针而非切片的值](https://3917758008-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M5h-t5ucz-h1GOVTTrU%2F-M5rDZ1KjJvLCDduUXEh%2F-M5rRtu8Gzyqyvrcq_pD%2Fcopy.jpg?alt=media\&token=a9bcff98-d346-455b-880b-faab7b2a5a7b)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://denglj.gitbook.io/essential-go/10-structs/duplicate-a-struct-make-a-copy.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
