Go 语言指针(Pointer)
指针是Go语言的重要特性之一,用于存储变量的内存地址,从而实现高效的数据访问和修改。
1. 指针的基本概念
指针是存储变量内存地址的变量,通过指针可以访问或修改变量的值。
(1) 指针的定义
var p *int // 声明一个指向 int 类型的指针变量
- *int 表示 p 是一个指向 int 类型变量的指针
- p 的默认值是 nil(空指针)
2. 获取变量地址(&)
可以使用 & 取地址符 获取变量的内存地址:
a := 42
p := &a // p 存储变量 a 的地址
fmt.Println(p) // 输出 a 的内存地址,例如:0xc0000100a0
3. 通过指针访问和修改值(*)
可以使用 * 解引用(Dereference) 指针,访问或修改指针指向的值:
a := 10
p := &a // 获取 a 的地址
fmt.Println(*p) // 访问 a 的值,输出 10
*p = 20 // 修改 a 的值
fmt.Println(a) // 输出 20
4. 指针的零值(nil)
未初始化的指针默认值为 nil,表示它没有指向任何变量:
var p *int
fmt.Println(p) // 输出 <nil>
使用 nil 指针会导致运行时错误(runtime error)。
5. 指针的应用
(1) 通过指针修改函数外部变量
在 Go 语言中,函数参数是值传递,如果想要修改外部变量的值,需要使用指针:
func updateValue(p *int) {
*p = 100 // 通过指针修改变量的值
}
func main() {
x := 10
updateValue(&x) // 传递变量的地址
fmt.Println(x) // 输出 100
}
(2) 指针与数组
指针可以指向数组的第一个元素:
arr := [3]int{1, 2, 3}
p := &arr[0] // 指向数组第一个元素
fmt.Println(*p) // 输出 1
p++ // 指针偏移,指向下一个元素(不推荐使用,Go 不支持指针运算)
推荐使用切片(slice)代替指针操作数组:
func modifySlice(s []int) {
s[0] = 100 // 直接修改原数组
}
func main() {
arr := []int{1, 2, 3}
modifySlice(arr)
fmt.Println(arr) // 输出 [100 2 3]
}
(3) 指针与new
new 用于分配内存,返回指针:
p := new(int) // 分配一个 int 类型的内存
*p = 42
fmt.Println(*p) // 输出 42
- new(int) 创建一个 int 类型变量,默认值为 0
- p 是指向该变量的指针
(4) 指针与struct
type Person struct {
Name string
Age int
}
func main() {
p := &Person{"Alice", 25}
fmt.Println(p.Name) // 直接访问字段,不需要 (*p).Name
}
Go 自动解引用 结构体指针,p.Name 等价于 (*p).Name。
6. 指针与unsafe包(高级用法)
Go 语言不支持指针运算,但 unsafe 包提供了低级指针操作:
package main
import (
"fmt"
"unsafe"
)
func main() {
x := [3]int{1, 2, 3}
p := unsafe.Pointer(&x[0]) // 获取数组首元素的指针
fmt.Println(p)
}
注意:unsafe 包涉及底层操作,慎用!
7. 指针 VS 值类型
方式 | 值传递 | 指针传递 |
传递方式 | 传递变量的副本 | 传递变量的地址 |
内存占用 | 复制整个值,占用更多内存 | 只复制地址,节省内存 |
修改变量 | 不影响原变量 | 可以修改原变量 |
适用场景 | 简单数据类型(int、float、string) | 需要修改原数据(结构体、大数据对象) |
示例:
func modifyValue(x int) {
x = 100
}
func modifyPointer(p *int) {
*p = 100
}
func main() {
a := 10
modifyValue(a)
fmt.Println(a) // 输出 10(未修改)
modifyPointer(&a)
fmt.Println(a) // 输出 100(已修改)
}
总结
操作 | 语法 | 作用 |
取变量地址 | p := &a | 获取变量 a 的地址 |
访问指针值 | *p | 访问 p 指向的值 |
修改指针值 | *p = 100 | 修改 p 指向的变量值 |
空指针 | var p *int = nil | p 为空指针 |
new 分配内存 | p := new(int) | 创建 int 变量并返回指针 |
结构体指针 | p := &Person{"Alice", 25} | 指向 struct |