跳到主要内容

Go 引用类型 vs 值类型速查表

Go 中传递变量时,有些类型会复制底层数据(值类型),有些只复制"指针/引用"(引用语义类型)。搞清楚这一点,能避免很多坑。

引用语义类型

以下类型传递时不会复制底层数据,修改会影响原始数据:

类型底层实现说明
map指向哈希表的指针直接传递即可,无需 &
slice{Ptr, Len, Cap} 结构体指针共享数组,但 Len/Cap 独立
channel指向通道结构的指针直接传递即可
pointer指针本身*T 类型
function函数引用函数值是引用
interface{类型信息, 数据指针}内部包含指针

值类型

以下类型传递时会完整复制,修改不影响原始数据:

类型说明
int, float64, bool基本数字和布尔类型
string不可变,传递时复制头部结构
array固定长度数组,注意不是 slice
struct结构体会完整复制所有字段

常见陷阱示例

1. slice:共享数组但 Len 独立

func modify(s []int) {
s[0] = 999 // ✅ 外部能看到,因为共享底层数组
s = append(s, 4) // ❌ 外部看不到,因为 Len 是独立的副本
}

func main() {
s := []int{1, 2, 3}
modify(s)
fmt.Println(s) // [999 2 3],长度还是 3
}

2. array:完全复制

func modify(a [3]int) {
a[0] = 999 // 修改的是副本
}

func main() {
a := [3]int{1, 2, 3}
modify(a)
fmt.Println(a) // [1 2 3],不变!
}

3. struct:完全复制

type Person struct {
Name string
}

func modify(p Person) {
p.Name = "Jerry" // 修改的是副本
}

func main() {
p := Person{Name: "Tom"}
modify(p)
fmt.Println(p.Name) // "Tom",不变!
}

4. map:直接传就行

func modify(m map[string]int) {
m["new"] = 100 // ✅ 外部能看到
}

func main() {
m := map[string]int{"a": 1}
modify(m)
fmt.Println(m) // map[a:1 new:100]
}

什么时候需要传指针?

场景是否需要指针
map❌ 不需要,直接传
slice 但要 append✅ 需要 *[]T 或返回新 slice
slice 只修改元素❌ 不需要
struct 要修改✅ 需要 *StructName
array 要修改✅ 需要 *[N]T
channel❌ 不需要,直接传

一句话总结

map、channel、function 直接传;slice 改元素直接传,append 要返回或传指针;struct、array 要修改必须传指针。

相关阅读