Go中所有函数传参均为值拷贝,值类型(如int、string、struct)复制全部数据,结构体含指针时仅复制指针值而非其所指内容,故仍属值类型;纯值类型完全独立,含引用字段的类型拷贝后可能共享底层数据。

Go 中所有函数传参都是值拷贝,值类型(如 int、string、struct、[3]int 等)也不例外——每次调用函数时,系统会把实参的完整数据复制一份,放进形参变量里。这个副本和原始变量在内存中完全独立,互不影响。
值类型拷贝的本质是“数据搬家”
值类型直接持有数据本身,不依赖外部存储。比如:
-
a := 42→ 内存中存的就是数字42 -
u := User{Name: "Alice", Age: 30}→ 整个结构体字段内容都连续存放在一块内存里
当它们被传入函数,Go 就把这一整块数据原样复制过去。哪怕结构体有 100 个字段,只要没含指针或引用类型,拷贝的就是全部字段的值。
拷贝行为可验证:地址完全不同
通过取地址能直观看到拷贝发生:
- 主函数里
&myStruct和函数内&p打印出的地址一定不同 - 哪怕结构体里有指针字段,
struct本体仍是值类型,整个结构体(含指针字段的值)被复制,但指针字段指向的底层数据不会被复制
也就是说:结构体本身是副本,但它内部的指针仍可能指向同一片堆内存——这属于浅拷贝范畴,不是值类型“失效”,而是它按规则忠实地拷贝了自己包含的所有内容(包括指针值)。
为什么设计成这样?安全与确定性优先
值拷贝让函数边界清晰:
代价是大结构体传参开销略高,这时就该考虑传指针——但注意:传指针仍是值拷贝(拷贝的是指针本身),只是副本指针和原指针指向同一地址。
哪些类型算“纯值类型”?关键看是否含引用字段
判断一个类型传参是否“真正隔离”,不能只看类型声明,而要看它实际持有的数据:
-
type A struct{ X int; Y string }→ 纯值类型,拷贝即完全独立 -
type B struct{ Data []int; Info *string }→ 表面是 struct,但含切片和指针,拷贝后仍共享底层数组和字符串内存
后者若需彻底隔离,就得手动深拷贝或用第三方库(如 copier 或 gob 编解码)。
基本上就这些。Go 不绕弯子:一律值拷贝,区别只在于“拷什么”——值类型拷数据,“引用类型”拷的是描述数据位置的句柄(比如 slice header、map header、指针值)。理解这点,就不会被“为什么改了切片却影响原变量”这类问题卡住。










