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. 表达"可选值"

相关推荐
爱吃大芒果2 小时前
Flutter 网络请求完全指南:Dio 封装与拦截器实战
开发语言·javascript·flutter·华为·harmonyos
云水木石2 小时前
Rust 语言开发的 Linux 桌面来了
linux·运维·开发语言·后端·rust
听风吟丶3 小时前
Java NIO 深度解析:从核心组件到高并发实战
java·开发语言·jvm
C++业余爱好者3 小时前
Java开发中Entity、VO、DTO、Form对象详解
java·开发语言
zmzb01033 小时前
C++课后习题训练记录Day50
开发语言·c++
froginwe113 小时前
`.toggleClass()` 方法详解
开发语言
lsx2024063 小时前
SQLite 附加数据库详解
开发语言
serendipity_hky3 小时前
【go语言 | 第4篇】goroutine模型和调度策略
后端·性能优化·golang
catchadmin3 小时前
PHP 开发者指南 如何在 Composer 中使用本地包
开发语言·php·composer