当前位置: 首页 > news >正文

Go 语言中指针介绍

指针是 Go 语言中一个非常核心的概念,也是许多从 PHP 等高级语言转过来的开发者最需要适应的一个点。不过别担心,Go 的指针比 C/C++ 中的指针要安全和简单得多。

理解指针的关键在于,它能让你在程序的不同部分共享和修改同一份数据,而不是传来传去的数据副本。

我们同样从简单到高阶,分场景来彻底搞懂它。


核心概念:什么是指针?

在探讨场景前,我们必须先建立一个清晰的心理模型。

想象一下,一个变量 v 就像一座房子 🏠,里面住着数据(比如数字 10)。

  • 变量 v 本身代表房子,可以直接访问里面的数据。
  • 指针 p 则是写着这座房子地址的一张纸条 📝。

指针(Pointer)本身也是一个变量,但它存储的不是普通数据,而是另一个变量的内存地址

Go 提供了两个核心操作符来使用指针:

  • & (取地址符): 当用在变量前面时(如 &v),它的意思是“给我这座房子的地址”。
  • * (解引用符): 当用在指针变量前面时(如 *p),它的意思是“去纸条上写的地址,把那座房子里的东西取出来”。它也用在类型声明中,表示一个指针类型(如 *int 表示一个指向整数的指针)。

场景一:基础且最常见的用法

1. 在函数中修改外部变量

这是你学习指针的首要理由,也是我们之前在“方法”部分遇到的指针接收者的原理。

  • 场景: 你需要写一个函数,这个函数要能修改传入的参数的值,而不是修改一个副本。例如,一个函数需要将外部的一个计数器加一。
  • 用法:
    a) 错误示范 (值传递)
    func addOne_Fail(num int) {num = num + 1 // 这里修改的是 num 的一个副本
    }func main() {x := 5addOne_Fail(x)fmt.Println(x) // 输出仍然是 5,原始的 x 没有被改变
    }
    
    b) 正确示范 (指针传递)
    // 参数是一个指向 int 的指针
    func addOne_Success(num *int) {// *num 的意思是“去 num 这个地址,把里面的值取出来”// 然后对这个值进行修改*num = *num + 1
    }func main() {x := 5// &x 的意思是“把 x 的地址传进去”addOne_Success(&x)fmt.Println(x) // 输出是 6,原始的 x 被成功修改了!
    }
    
    我们之前学的 func (u *User) HaveBirthday() 就是这个原理。u 接收的是 User 实例的地址,所以方法能修改原始的 User

场景二:中阶/性能考量

2. 避免大数据结构的值拷贝

当你的结构体非常大时,在函数间以“值传递”的方式传来传去,会产生巨大的性能开销。因为每一次函数调用,Go 都需要完整地复制一遍整个结构体。

  • 场景:
    • 你有一个包含大量字段的配置结构体 Config,需要把它传递给多个函数去读取其中的不同部分。
    • 你有一个包含大数据块(比如一个图片或一段音频)的结构体。
  • 用法: 通过传递结构体的指针,你实际上只复制了一个非常小的内存地址(通常是 8 字节),而不是整个庞大的结构体数据。
    type BigStruct struct {// 假设这里有很多字段,占用很大内存data [1024 * 10]byte // 10KB 的数据
    }// 低效的方式:每次调用都会复制 10KB 的数据
    func processByValue(s BigStruct) { /* ... */ }// 高效的方式:只复制一个 8 字节的指针
    func processByPointer(s *BigStruct) { /* ... */ }func main() {data := BigStruct{}processByPointer(&data) // 这是更推荐的做法
    }
    
    经验法则:当你的结构体比较大,或者需要在多处共享和修改时,优先使用指针。

场景三:高阶/地道用法

3. 表示“可选”或“缺失”的值

一个指针的零值是 nil。这个特性非常有用,可以用来区分“一个值为零”和“根本没有提供值”这两种情况。

  • 场景: 你在设计一个用于更新用户信息的 API。用户只想更新他的年龄,而不想改动姓名。如果你的更新结构体是 struct { Name string; Age int },那么传过来的 JSON {"age": 30} 会导致 Name 字段是空字符串 ""。你是要更新用户的姓名为空,还是用户根本没提供姓名?这就有歧义了。
  • 用法: 将结构体字段定义为指针类型。如果 JSON 中没有这个字段,那么指针的值就是 nil
    type UpdateUserPayload struct {Name *string `json:"name,omitempty"`Age  *int    `json:"age,omitempty"`
    }func main() {// 假设只收到了 age 字段jsonStr := `{"age": 31}`var payload UpdateUserPayloadjson.Unmarshal([]byte(jsonStr), &payload)if payload.Name != nil {fmt.Println("用户想要更新姓名为:", *payload.Name)} else {fmt.Println("用户没有提供新的姓名。")}if payload.Age != nil {fmt.Println("用户想要更新年龄为:", *payload.Age)} else {fmt.Println("用户没有提供新的年龄。")}
    }
    
    输出会是:
    用户没有提供新的姓名。
    用户想要更新年龄为: 31
    
    通过检查指针是否为 nil,我们就能准确地知道用户到底想更新哪些字段。
4. 构建链式数据结构

像链表、树这样的数据结构,其节点之间就是通过指针连接起来的。

  • 场景: 实现一个链表或二叉树。
  • 用法: 结构体中包含一个或多个指向同类型结构体的指针。nil 指针自然地表示链表的末尾或树的叶子节点。
    type Node struct {Value intNext  *Node // 指向下一个节点的指针
    }func main() {node1 := Node{Value: 10}node2 := Node{Value: 20}node1.Next = &node2 // node1 的 Next 指针指向 node2 的地址// 这样,node1 和 node2 就连接起来了fmt.Println(node1.Value)        // 10fmt.Println(node1.Next.Value)   // 通过指针访问下一个节点的值: 20
    }
    

总结

对于有 PHP 背景的你来说,可以这样简单理解:

  • 当你需要在函数或方法内部修改外部的变量时,使用指针。
  • 当你传递一个很大的结构体,想避免复制开销时,使用指针。
  • 当你需要表达一个值**“可能不存在”**时,使用指针。

Go 的指针是一个强大但清晰的工具,它让你能更精确地控制程序的内存和数据流。

http://www.dtcms.com/a/419119.html

相关文章:

  • 权重的网站建设网站有哪些内容
  • vxe-grid @edit-closed方法不被执行或者叫不触发
  • CF Yamakasi (前缀和+双指针)
  • 机器学习-第三章 线性模型
  • 新手想做网站赚钱app制作开发公司怎么收费
  • 现代Web存储技术(二):存储容量规划与传统方案对比
  • PyTorch实战(8)——图像描述生成
  • App Store 上架完整流程解析,iOS 应用发布步骤、ipa 文件上传工具、TestFlight 测试与苹果审核经验
  • stm32和Zynq的中断抢占机制
  • iOS App 混淆实战,在源码不可用情况下的成品加固与测试流程
  • Python爬虫技术:招标信息抓取与关键词过滤 (1)
  • 莞城网站推广wordpress图片并列排
  • 塘厦仿做网站wordpress和jwplayer
  • 嵌入式 - 内核驱动3 - class/device | misc | ioctl |device/driver
  • Matlab通过GUI实现点云的双边(Bilateral)滤波(附最简版)
  • 4-5〔O҉S҉C҉P҉ ◈ 研记〕❘ WEB应用攻击▸远程文件包含漏洞
  • 怎么在淘宝上做网站中交建设集团网站
  • 在线查看网站源码中国最新新闻
  • 轴状态读取(运动控制系列)
  • quic的拥塞控制
  • 【模型系列】Human-in-the-Loop
  • AI项目问题总结大全
  • 【linux内核驱动day03】
  • Accelerate基本使用
  • Day75 基本情报技术者 单词表10 ネットワーク応用
  • 企业网站美化做常州美食网站首页的背景图
  • 网站建设设计的流程wordpress的搭建教程 pdf
  • 页网站腾讯云学生机做网站
  • C++ 模板(Template)基础与应用
  • Flask实战指南:从基础到高阶的完整开发流程