go 里面的指针
指针
在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样:
a := 10
p := &a // p 是一个指向 a 的指针
fmt.Println(*p) // 输出 10,通过指针解引用
• &a 表示获取变量 a 的地址
- p 表示通过地址访问对应的值
特性 | C 语言 | Go 语言 |
---|---|---|
指针声明 | int *p | var p *int |
指针的指针 | ✅ 支持如 int **pp | ❌ 不推荐/不常用(语法上不直接暴露) |
指针运算 | ✅ 可对指针加减偏移 | ❌ 不允许指针运算 |
内存分配 | malloc, free | new, make, GC 自动管理 |
野指针问题 | ⚠️ 常见 | ✅ 几乎不存在(有 GC) |
🚫 Go 不支持的指针特性(与 C 相比)
- ❌ 不支持指针算术(如 p + 1)
- ❌ 不支持指针的指针的广泛操作(虽然语法允许 **T,但极少使用)
- ❌ 不能随便转换指针类型(除非用 unsafe 包)
应用场景
- 函数传参避免拷贝(提升性能)
func modify(x *int) {*x = 100
}a := 5
modify(&a)
fmt.Println(a) // 100
- 结构体指针
type Person struct {Name string
}func changeName(p *Person) {p.Name = "Alice">>>>> 等价于(*p).Name = "Alice"
}
在 Go 中,如果你有一个指向结构体的指针 p *Person,Go 会自动帮你解引用:
type Person struct {Name string
}func changeName(p *Person) {// 实际上这是 (*p).Name = "Alice"p.Name = "Alice"
}func main() {person := Person{Name: "Bob"}changeName(&person)fmt.Println(person.Name) // 输出:Alice
}
自动解引用访问结构体字段,是 Go 的语法特性,目的是让代码更简洁、易懂
3.切片、map、channel 等内置类型是“引用类型”,无需显式指针
Go 的指针机制和 C 类似,但更安全,限制更多,没有“指针的指针”这种复杂操作,也不支持指针算术,更加鼓励值语义 + 显式传指针来控制性能和可变性。
Go 是值传递(pass-by-value)的语言,但可以传递“指针值”。
*func modify(x int)
这个函数的参数 x 是一个“指向 int 的指针”,也就是说它接收的是一个 *int 类型的值(本质上是内存地址)。
modify(&a)
a := 5
modify(&a) // &a 是变量 a 的内存地址(类型是 *int)>>>>>modify(&a) 是把变量 a 的地址作为值传进函数 modify(x *int),
>>>>>函数通过指针 x 修改了原变量的值。
- &a:取变量 a 的内存地址,类型是 *int
- modify(&a):把这个地址传给函数 modify 的参数 x
传进去的是 a 的地址(而不是 a 的值),但这个地址本身是按值传入的,就像传入一个 int、string、float64 一样。
表达式 | 意义 | 类型 | 说明 |
---|---|---|---|
a | 变量本身 | int | 值是 5 |
&a | a 的地址 | *int | 值是内存地址,例如 0x1400012fc08 |
x | 函数参数,接收到 &a | *int | 是地址 |
*x | 取出地址指向的内容 | int | 是 a 的值 |
*x = 100 | 改变地址指向的值 | — | 把 a 改为 100 |
// a 是个箱子,里面装了 5
a := 5// &a 是这个箱子的编号(地址),我们把编号给了 modify 函数
modify(&a)// modify 函数通过编号找到了箱子,把里面的 5 改成了 100
方式 | 描述 | 会修改原变量? |
---|---|---|
值传递 | 复制了一份值(浅拷贝) | ❌ 否 |
指针传递 | 传递的是地址本身 | ✅ 是 |
深拷贝 | 创建了新的独立值(递归复制所有内容) | ❌(除非修改返回值) |
误区 | 真相 |
---|---|
Go 是引用传递 | ❌ Go 是值传递,包括传指针也是“传值传地址” |
new 和 make 一样 | ❌ new 分配内存,make 初始化引用类型 |
指针越多越高效 | ❌ 指针会导致逃逸,频繁使用反而性能差 |
指针不能用于方法接收者 | ❌ 指针接收者用于修改对象、避免复制结构体 |