Go 语言中的指针详解
包含字段与方法的简化写法
在 Go 语言中,指针是高效操作数据、避免大对象拷贝的重要工具。本文将详细讲解 Go 中指针相关的几个关键概念:
&:取地址*T:声明指针类型*p:解引用指针- 结构体指针可以使用
ptr.Field和ptr.Method()的简化写法 - 是否支持多级指针如
**T
一、基本操作符解释
1. &:取地址
用于获取变量的内存地址。
a := 42
p := &a // p 是一个指向 int 的指针
此时 p 类型为 *int。
2. *T:声明指针类型
var p *int // 声明一个指向 int 的指针
这里的 * 表示这是一个指针类型。
3. *p:解引用指针
fmt.Println(*p) // 输出 42
*p = 100 // 修改 a 的值为 100
表示访问指针所指向的实际值。
二、结构体指针的简化写法
Go 提供了两个非常实用的语法糖:
✅ 1. 字段访问:ptr.Field
type Person struct {
Name string
}
func main() {
p := Person{Name: "Alice"}
ptr := &p
fmt.Println(ptr.Name) // 合法,等价于 (*ptr).Name
}
Go 编译器会自动将 ptr.Name 转换为 (*ptr).Name。
✅ 2. 方法调用:ptr.Method()
func (p *Person) SayHello() {
fmt.Println("Hello, ", p.Name)
}
func main() {
p := &Person{Name: "Alice"}
p.SayHello() // 合法,等价于 (*p).SayHello()
}
Go 允许你直接使用指针调用方法,不需要显式解引用。
这是 Go 特有的设计特性,目的是让代码更简洁、易读。
三、函数参数传递与指针
如果希望函数能修改原始变量,通常需要传入指针。
func updateValue(v *int) {
*v = 100
}
func main() {
a := 10
updateValue(&a)
fmt.Println(a) // 输出 100
}
四、是否支持 **T 这样的多级指针?
Go 支持多级指针,例如:
func main() {
a := 10
p := &a
pp := &p
fmt.Println(**pp) // 输出 10
**pp = 20
fmt.Println(a) // 输出 20
}
虽然语法上支持 **T,但在实际开发中不推荐使用,因为会增加理解成本和出错概率。
五、总结对比表
| 操作符/语法 | 使用场景 | 示例 | 说明 |
|---|---|---|---|
& | 取变量地址 | p := &a | 获取变量 a 的内存地址 |
*T | 声明指针类型 | var p *int | p 是一个指向 int 的指针 |
*p | 解引用指针 | fmt.Println(*p) | 获取 p 所指向的值 |
ptr.Field | 访问结构体字段 | ptr.Name | 等价于 (*ptr).Name |
ptr.Method() | 调用结构体方法 | ptr.SayHello() | 等价于 (*ptr).SayHello() |
**T | 多级指针 | var pp **int | 支持但不推荐使用 |
六、最佳实践建议
- ✅ 使用指针避免大对象拷贝,提高性能。
- ✅ 在函数中修改外部变量时,传入指针。
- ✅ 对结构体指针使用
ptr.Field和ptr.Method()简化写法,提升可读性。 - ⚠️ 避免使用多级指针,除非必要。
- ❌ 不要对非结构体指针使用
.Field或.Method()写法。