0

0

Go 中如何在函数内安全重赋值外部变量的引用:指针与指针接收器的正确用法

花韻仙語

花韻仙語

发布时间:2026-01-25 13:58:14

|

758人浏览过

|

来源于php中文网

原创

Go 中如何在函数内安全重赋值外部变量的引用:指针与指针接收器的正确用法

本文详解 go 语言中通过函数修改调用方变量值的两种主流方式——传入单级指针与使用指针方法,并对比其适用场景、安全性及 go 风格规范,帮助开发者避免常见内存误用。

在 Go 中,若需在函数内部“替换”调用方持有的变量值(而非仅修改其字段),必须操作该变量的地址。关键在于:Go 所有参数都是值传递,要影响外部变量,必须显式传递其地址(即指针)。上面示例中的 assign1 和 assign2 均实现了这一目标,但实现机制与语义重点不同,需结合场景谨慎选择。

✅ 推荐方式:单级指针参数(assign1 的优化版)

原始 assign1 使用了 **Blob(指针的指针),实属冗余。实际上,只需一级指针即可完成值替换:

func assign1(b *Blob) {
    *b = Blob{"Internally created by assign1"} // 直接解引用并赋新结构体值
}

func main() {
    x := Blob{"Hello World"} // 注意:此处是值类型变量,非指针
    assign1(&x)              // 传入其地址
    fmt.Printf("x = %+v\n", x) // 输出:{Message:Internally created by assign1}
}

优势

  • 简洁明确:意图清晰——“我将用一个新 Blob 覆盖你传入的变量”;
  • 安全高效:无需额外指针层级,避免空指针解引用风险(如 bb == nil 时 *bb = ... 会 panic);
  • 符合 Go 习惯:标准库中类似操作(如 fmt.Sscanf、json.Unmarshal)均采用 *T 参数形式。

⚠️ 注意:调用时必须确保传入有效地址(&x),且 x 本身可寻址(不能是字面量或临时表达式结果,如 assign1(&Blob{}) 合法,但 assign1(&struct{}{}) 在某些上下文中可能受限)。

⚠️ 特定场景:指针接收器方法(assign2 的本质)

assign2 并非“错误”,而是服务于另一类设计模式:

func (b *Blob) assign2() {
    *b = Blob{"Internally created by assign2"} // 修改接收器指向的整个值
}

这本质上等价于:

降重鸟
降重鸟

要想效果好,就用降重鸟。AI改写智能降低AIGC率和重复率。

下载
func assign2(b *Blob) { *b = Blob{...} }

但它的意义在于将状态重置行为封装为类型契约的一部分。典型用例包括:

  • 完整状态覆盖:如 Counter 的 Reset()、bytes.Buffer 的 Reset();
  • 反序列化接口:encoding/gob.GobDecoder 和 encoding/json.Unmarshaler 要求实现 func (x *T) GobDecode([]byte) error,其核心就是用新数据完全替换 *x 指向的内容;
  • 资源复用:避免频繁分配,例如重置一个已分配的切片或结构体实例。

? 关键约束

  • 必须通过指针调用(x2.assign2() 中 x2 是值,Go 自动取地址;若 x2 是 nil *Blob 则 panic);
  • 仅适用于整个值的语义性替换,而非部分字段更新(后者应直接 b.Message = "new");
  • 若类型暴露为接口,此方式便于统一抽象(如定义 type Resetter interface { Reset() })。

? 总结:如何选择?

场景 推荐方式 示例
通用工具函数(独立于类型定义) 单级指针参数 func f(*T) json.Unmarshal(data, &v)
类型专属的完整状态重置 指针接收器方法 func (t *T) Reset() buf.Reset(), counter.Reset()
需要满足标准接口(如 Unmarshaler) 必须用指针接收器方法 func (x *MyType) UnmarshalJSON([]byte) error

避免

  • 使用 **T(双指针)——除非极特殊场景(如需动态改变指针本身指向的地址,且该地址由调用方管理);
  • 对值接收器方法尝试修改 *t(编译失败)或对不可寻址值调用指针方法(运行时 panic)。

最终,Go 的指针设计强调明确性与可控性:无论是 *T 参数还是 (*T) Method,其本质都是对内存地址的操作。理解“值传递指针”这一底层逻辑,就能写出既安全又符合 Go 习惯的代码。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

417

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

535

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

311

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

76

2025.09.10

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

188

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

291

2023.10.25

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

200

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

190

2025.07.04

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

45

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.5万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号