指针
约 474 字大约 2 分钟
2025-04-17
指针基础
指针保存了一个值的内存地址。使用 & 取地址,* 解引用。
a := 13
p := &a // p 是指向 a 的指针
fmt.Println(p) // 0xc0000...
fmt.Println(*p) // 13(解引用)结构体指针
结构体字段可以通过结构体指针直接访问,无需显式解引用。
type Vertex struct {
a int
b int
}
func main() {
v := Vertex{34, 56}
p := &v
p.b = 25 // 等价于 (*p).b = 25
p.a = 78
fmt.Println(v) // {78, 25}
}Go 自动对指针进行解引用,所以 p.b 直接访问结构体字段,写法更简洁。
结构体初始化示例
type Vertex struct {
a int
b int
}
func main() {
v := Vertex{} // 零值初始化
var (
a = Vertex{1, 2}
b = Vertex{a: 4} // 只指定 a 字段
c = Vertex{5, 6}
)
fmt.Println(a, b, c, v.b)
}指针与函数参数
通过指针可以在函数内部修改外部变量的值。
func main() {
name := "xiaoming"
// 值传递:原值不变
valueFunc(name)
fmt.Println(name) // xiaoming
// 指针传递:原值被修改
pointerFunc(&name)
fmt.Println(name) // lisi
}
func valueFunc(s string) {
s = "zhangsan" // 只修改副本
}
func pointerFunc(name *string) {
*name = "lisi" // 通过指针修改原值
}指针副本的本质
Go 中的所有传递都是值传递。即使是指针传递,也是先创建一个指针的副本,副本指针与原指针指向同一个地址:
func checkPointer(p *string) {
fmt.Printf("指针地址(副本): %p\n", &p) // 与原指针地址不同
}
func main() {
name := "xiaoming"
p := &name
fmt.Printf("原指针地址: %p\n", &p) // 与原指针地址不同
checkPointer(p)
}核心理解
&取地址运算符,获取变量的内存地址*解引用运算符,获取指针指向地址的值- 结构体指针可直接用
.访问字段(Go 自动解引用) - Go 中一切都是值传递,指针传递的本质是传递指针值的副本
