Go 语言指针

Go 里的指针不复杂,但非常实用,不像 C/C++ 那么危险,也不像 Java 那样完全看不到。

一、Go 指针是什么

1. 指针的本质

指针 = 变量的内存地址

Go 复制代码
var a int = 10
var p *int = &a
  • a:值是 10

  • &a:a 的地址

  • p:指向 a 的指针

  • *p:通过指针访问 a 的值

Go 复制代码
fmt.Println(a)   // 10
fmt.Println(p)   // 0xc00001a0a8(地址)
fmt.Println(*p)  // 10

口诀:
& 取地址, 解引用*

2. Go 指针的"安全边界"

和 C/C++ 不同,Go:

  • 不能指针运算(p++ 不存在)

  • 不能随便转类型

  • 有 GC(不用手动 free)

  • 空指针是 nil

Go 复制代码
var p *int
fmt.Println(p == nil) // true

二、Go 指针使用场景

1. 修改函数外的变量(非常核心)

❌ 值传递(改不到外面):

Go 复制代码
func add(a int) {
    a++
}

func main() {
    x := 10
    add(x)
    fmt.Println(x) // 10
}

✅ 指针传递:

Go 复制代码
func add(a *int) {
    *a++
}

func main() {
    x := 10
    add(&x)
    fmt.Println(x) // 11
}

Go 只有值传递,但"指针的值"可以指向同一块内存

2 结构体 + 指针(Go 的高频用法)

Go 复制代码
type User struct {
    Name string
    Age  int
}

func grow(u *User) {
    u.Age++
}

func main() {
    u := User{Name: "Tom", Age: 18}
    grow(&u)
    fmt.Println(u.Age) // 19
}

注意: Go 一个很贴心的地方:

Go 复制代码
u.Age++      // 等价于 (*u).Age++

Go 自动帮解引用,不需要满屏 *

3. new / & 的区别

Go 复制代码
p1 := new(int) // *int,值是 0
p2 := &User{} // *User

等价写法:

Go 复制代码
var a int
p := &a

一般习惯:

  • 基本类型:&

  • 结构体:&User{} 或构造函数

三、Go 指针的核心使用场景

场景 1:需要修改对象本身(最常见)

Go 复制代码
func updateName(u *User) {
    u.Name = "Jack"
}

场景 2:避免大对象拷贝(性能 & 内存)

Go 复制代码
type BigStruct struct {
    Data [100000]int
}

func process(b *BigStruct) {
    // 不拷贝 100000 个 int
}

场景 3:区分"没传"和"传了零值"

这个在 API / JSON / DB 特别重要

Go 复制代码
type Req struct {
    Age *int `json:"age"`
}
  • nil → 前端没传

  • 0 → 前端明确传了 0

场景 4:方法接收者用指针(Go 面向对象)

Go 复制代码
func (u *User) Grow() {
    u.Age++
}

什么时候用指针接收者?

  • 需要修改对象

  • 结构体比较大

  • 保证方法一致性(推荐)

官方建议:一个结构体,要么全指针接收者,要么全值接收者

场景 5:与 interface 配合

Go 复制代码
type Writer interface {
    Write()
}

type File struct{}

func (f *File) Write() {}

var w Writer
w = &File{} // 正确

这样不行,因为方法在 *File 上:

Go 复制代码
w = File{} // 没实现接口

场景 6:并发 & 共享状态

需谨慎使用

Go 复制代码
var count int
var mu sync.Mutex

func inc() {
    mu.Lock()
    count++
    mu.Unlock()
}

虽然不是"显式指针",但底层都是共享内存 + 地址

四、Go 指针 vs Java/C++

对比 Go Java C++
手动内存
指针运算
空指针 nil null nullptr
参数传递 值传递 值传递(引用语义) 值/引用

Go 指针 = "受控版 C 指针 + Java 引用的灵活性"

五、新手常见坑

❌ 对 map / slice 再取指针

Go 复制代码
func f(m *map[string]int) // 一般没必要

因为:

  • map / slice 本身就是"引用类型"

  • 直接传就能改

❌ nil 指针解引用

Go 复制代码
var u *User
u.Age = 10 // panic

一定要先初始化。

六、总结

Go 指针的目标只有三个:

  1. 修改原数据

  2. 减少拷贝

  3. 表达"可选值"

相关推荐
Dovis(誓平步青云)35 分钟前
《QT学习第四篇:常见事件与UDP、TCP、文件系统、(锁、信号量、条件变量》
c语言·开发语言·汇编·qt
isyangli_blog9 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008119 小时前
FastAPI APIRouter
开发语言·python
Benszen9 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆9 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木9 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
杨充10 小时前
1.3 浮点型数据设计灵魂
开发语言·python·算法
噜噜噜阿鲁~10 小时前
python学习笔记 | 11.3、面向对象高级编程-多重继承
java·开发语言
basketball61610 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
春生野草10 小时前
反射、Tomcat执行
java·开发语言