在Golang中,指针是用来存储变量内存地址的特殊变量,通过指针可以直接操作对应内存地址中的数据,在需要修改函数外部变量、减少大对象拷贝开销等场景中会经常用到。理解指针的声明和取地址方法是掌握Golang指针的基础。

Golang指针的基础概念
每一个变量在运行时都会被分配一块内存空间,这块空间有对应的内存地址。指针变量的作用就是保存其他变量的内存地址,我们可以通过指针间接访问或修改对应地址中存储的值。Golang的指针相比C/C++的指针更加安全,不支持指针的算术运算,也不允许直接操作未分配的内存。
指针的声明方法
在Golang中声明指针需要用到*符号,语法格式为var 指针变量名 *指针指向的数据类型,不同类型的指针不能互相赋值,比如int类型的指针不能指向string类型的变量。
常见的指针声明方式有以下几种:
- 声明一个未初始化的指针,此时指针的默认值为
nil,表示不指向任何有效内存地址 - 声明指针的同时进行初始化,让它指向一个已有的变量
- 使用短变量声明的方式定义指针
下面是具体的声明示例:
package main
import "fmt"
func main() {
// 声明一个int类型的指针,默认值为nil
var ptr1 *int
fmt.Println("ptr1的值:", ptr1) // 输出 <nil>
// 声明一个int变量
var num int = 10
// 声明指针并初始化,指向num变量
var ptr2 *int = &num
fmt.Println("ptr2指向的地址:", ptr2)
// 短变量声明方式定义指针
ptr3 := &num
fmt.Println("ptr3指向的地址:", ptr3)
}
取地址方法
在Golang中获取变量的内存地址需要使用取地址符&,将&放在变量名前面,就可以得到该变量的内存地址,这个地址可以直接赋值给对应类型的指针变量。
取地址操作的使用场景很多,比如把变量的地址传递给函数,让函数内部可以修改外部变量的值,或者把大结构体的地址传递给函数,减少值拷贝的开销。
下面是取地址操作的示例:
package main
import "fmt"
func main() {
var name string = "Golang指针教程"
// 获取name变量的地址,赋值给string类型的指针
var namePtr *string = &name
fmt.Println("name变量的地址:", &name)
fmt.Println("namePtr存储的地址:", namePtr)
fmt.Println("通过指针获取name的值:", *namePtr)
// 修改变量的值
*namePtr = "Golang指针进阶"
fmt.Println("修改后name的值:", name)
}
指针的常见使用场景
函数参数传递
当我们需要在函数内部修改外部变量的值时,可以传递变量的指针给函数,这样函数操作的就是外部变量的内存地址,修改会直接生效。
package main
import "fmt"
// 接收int类型指针的函数,修改指针指向的值
func updateValue(ptr *int) {
*ptr = 20
}
func main() {
var score int = 10
fmt.Println("修改前score的值:", score)
updateValue(&score)
fmt.Println("修改后score的值:", score)
}
减少大对象拷贝开销
如果结构体等类型的数据体积较大,值传递会拷贝整个对象,开销较高,传递指针只需要拷贝地址,效率更高。
package main
import "fmt"
// 定义一个较大的结构体
type BigStruct struct {
Data [1000]int
}
// 接收结构体指针的函数
func processStruct(ptr *BigStruct) {
ptr.Data[0] = 100
}
func main() {
var big BigStruct
processStruct(&big)
fmt.Println("big.Data[0]的值:", big.Data[0])
}
指针使用的注意事项
- 不要对
nil指针进行取值操作,否则会触发运行时 panic,使用前可以先判断指针是否为nil - Golang不支持指针的算术运算,比如不能对指针进行加减操作,避免操作到非法内存
- 不要返回局部变量的指针,局部变量在函数结束后会被销毁,返回的指针指向的内存可能已经被回收,访问会出现错误
- 指针类型要和指向的变量类型严格匹配,不同类型的指针不能互相赋值或比较
指针是Golang中提升程序效率的重要工具,合理使用指针可以减少不必要的内存拷贝,同时也能实现函数内外数据的共享修改,但使用时一定要注意指针的有效性,避免出现空指针异常等问题。