Golang中的指针是用来存储变量内存地址的特殊类型,和C/C++的指针相比,Golang的指针不支持指针运算,使用起来更加安全,掌握指针的声明与初始化是理解Golang变量传递机制的基础。

Golang指针的声明语法
声明指针的核心是使用*符号,格式为var 指针变量名 *指针指向的类型,声明后的指针默认值为nil,表示不指向任何有效内存地址。
下面是几种常见的指针声明示例:
package main
import "fmt"
func main() {
// 声明一个指向int类型的指针
var intPtr *int
// 声明一个指向string类型的指针
var strPtr *string
// 声明一个指向自定义结构体类型的指针
type User struct {
Name string
Age int
}
var userPtr *User
fmt.Println(intPtr) // 输出:<nil>
fmt.Println(strPtr) // 输出:<nil>
fmt.Println(userPtr) // 输出:<nil>
}
Golang指针的初始化方法
指针声明后不能直接使用,需要先完成初始化,指向一个有效的变量内存地址,常见的初始化方式有以下几种。
1. 使用取地址符&初始化
通过&符号可以获取普通变量的内存地址,将其赋值给同类型的指针即可完成初始化,这是最常用的初始化方式。
package main
import "fmt"
func main() {
num := 10
// 将num的地址赋值给intPtr指针
var intPtr *int = &num
// 短变量声明方式初始化指针
strPtr := &"hello"
fmt.Println(intPtr) // 输出:0xc00001a0b8(地址值随运行环境变化)
fmt.Println(*intPtr) // 输出:10,通过*解引用获取指针指向的值
fmt.Println(strPtr) // 输出:0xc000010240(地址值随运行环境变化)
fmt.Println(*strPtr) // 输出:hello
}
2. 使用new函数初始化
Golang内置的new函数可以分配对应类型的内存空间,返回该内存空间的指针,new函数的参数是类型,返回值是对应类型的指针。
package main
import "fmt"
func main() {
// new函数分配int类型的内存,返回*int指针
intPtr := new(int)
// new函数分配结构体类型的内存,返回*User指针
type User struct {
Name string
Age int
}
userPtr := new(User)
fmt.Println(intPtr) // 输出:0xc00001a0b8(地址值随运行环境变化)
fmt.Println(*intPtr) // 输出:0,new分配的内存会被初始化为零值
fmt.Println(userPtr) // 输出:&{ 0}
// 可以直接通过指针修改结构体字段
userPtr.Name = "张三"
userPtr.Age = 20
fmt.Println(*userPtr) // 输出:{张三 20}
}
Golang指针常见写法
1. 指针作为函数参数
当需要在函数内部修改外部变量的值时,通常将指针作为函数参数传递,避免值传递带来的拷贝开销。
package main
import "fmt"
// 函数接收int类型指针,修改指针指向的值
func modifyNum(numPtr *int) {
*numPtr = 20
}
func main() {
num := 10
fmt.Println("修改前:", num) // 输出:修改前: 10
modifyNum(&num)
fmt.Println("修改后:", num) // 输出:修改后: 20
}
2. 指针接收者的方法定义
给结构体定义方法时,如果方法需要修改结构体的字段,或者结构体体积较大需要避免拷贝,通常会使用指针作为接收者。
package main
import "fmt"
type User struct {
Name string
Age int
}
// 指针接收者方法,修改结构体字段
func (u *User) UpdateAge(newAge int) {
u.Age = newAge
}
// 值接收者方法,不修改结构体字段
func (u User) GetInfo() string {
return fmt.Sprintf("姓名:%s,年龄:%d", u.Name, u.Age)
}
func main() {
user := User{Name: "李四", Age: 18}
fmt.Println(user.GetInfo()) // 输出:姓名:李四,年龄:18
user.UpdateAge(22)
fmt.Println(user.GetInfo()) // 输出:姓名:李四,年龄:22
}
3. 判断指针是否为空
使用指针前通常需要判断指针是否为nil,避免解引用空指针导致程序崩溃。
package main
import "fmt"
func main() {
var ptr *int
if ptr == nil {
fmt.Println("指针为空,未初始化")
}
num := 10
ptr = &num
if ptr != nil {
fmt.Println("指针已初始化,指向的值为:", *ptr)
}
}
指针使用注意事项
- 不要解引用
nil指针,否则会触发panic - Golang的指针不支持指针运算,不能像C语言那样对指针进行加减操作
- 函数返回局部变量的指针是安全的,Golang的逃逸分析会将局部变量分配到堆上
- 结构体指针访问字段时可以直接使用
.操作符,不需要先解引用再访问
指针的核心作用是减少值拷贝的开销,以及实现函数内部对外部变量的修改,不需要过度使用指针,普通场景下值传递已经足够满足需求。