0

0

如何在Golang中掌握指针赋值与拷贝_Golang地址传递与值传递区别

P粉602998670

P粉602998670

发布时间:2026-01-05 07:39:23

|

795人浏览过

|

来源于php中文网

原创

Go中只有值传递,&x取地址得T类型值,p解引用读取指向的值;传指针本质是传地址值副本,修改指针本身不影响原变量。

如何在golang中掌握指针赋值与拷贝_golang地址传递与值传递区别

Go 里 &* 到底在干啥

Go 中没有“引用传递”,只有值传递;但你可以传一个指针类型的值,它本身存的是地址。所以关键不是“传什么”,而是“传进去的东西是什么类型”。&x 取出变量 x 的内存地址,得到一个 *T 类型的值;*p 是解引用,从地址 p 读出它指向的 T 类型的值。

常见错误是以为写了 func f(p *int) { p = &y } 就能改外面的指针变量本身——其实不能,因为 p*int 的副本,你只是把它内部存的地址换掉了,原变量没变。

  • &x 的结果是一个新生成的指针值(地址),类型为 *T
  • *p 操作需要 p != nil,否则 panic: invalid memory address or nil pointer dereference
  • 结构体字面量里用 &S{...} 得到的是指向新分配结构体的指针,不是对已有变量取地址

函数参数传 *T 还是 T?看这三点

决定是否用指针传参,不看“要不要修改”,而看三件事:数据大小、是否真要修改原值、API 一致性。

  • 小类型(如 intbool[3]int)传值开销小,优先传值;大结构体(比如含 []byte 或几十字段)传指针避免拷贝
  • 如果函数逻辑上“必须修改调用方状态”,比如 json.Unmarshal(&v),那就得传 *T;否则传值更安全、更易测试
  • 同个类型的方法集最好统一:如果已经有 (*T).Method(),那其他函数也建议接收 *T,避免混用造成理解成本
type User struct {
	Name string
	Age  int
}

func updateUser(u *User) { // 明确表示会改 u 指向的值
	u.Name = "Alice"
}
func copyUser(u User) User { // 不动原值,返回新副本
	u.Name = "Bob"
	return u
}

切片、map、channel 为什么“像引用”但仍是值传递

它们底层都是结构体(header),包含指针字段。例如 slice 实际是 struct{ ptr *elem, len, cap }。传 slice 时,这个 header 被完整拷贝,但其中的 ptr 字段仍指向同一块底层数组——所以改元素会反映到原 slice,但做 s = append(s, x) 可能导致扩容,新 header 的 ptr 就指向别处了,原 slice 不受影响。

Transor
Transor

专业的AI翻译工具,支持网页、字幕、PDF、图片实时翻译

下载

立即学习go语言免费学习笔记(深入)”;

  • mapchannel 同理:header 拷贝,内部指针共享;但 make(map[int]int) 返回的是 header 值,不是指针
  • 想让函数彻底控制底层数组(比如强制扩容并让调用方看到),必须传 *[]T,即指向切片 header 的指针
  • 常见坑:func badAppend(s []int) { s = append(s, 99) } —— 外面的 slice 完全不受影响
func goodAppend(s *[]int) {
	*s = append(*s, 99)
}
nums := []int{1, 2}
goodAppend(&nums) // nums 现在是 [1 2 99]

什么时候必须用 new(T)&T{}

new(T) 返回 *T,且把内存清零;&T{} 也返回 *T,但按字段顺序初始化(未写的字段仍为零值)。二者都不常用,多数时候直接写 &User{Name: "X"} 更清晰。

  • new(T) 唯一不可替代场景:你需要一个零值指针,但 T 没有字面量语法(比如接口、函数类型)——但这种情况极少
  • &T{} 常用于初始化结构体,尤其字段多或含嵌套时;注意 &struct{X int}{1} 合法,但 struct{X int}{1} 是值,不是地址
  • 不要为了“统一风格”而滥用:var x *int; x = new(int) 不如 x := new(int) 直观,更不如 var x int; px := &x 明确
真正容易被忽略的是:Go 的“值传递”规则贯穿一切,包括 interface{}。当你把 *T 赋给 interface{},传进去的仍是那个指针值的副本——但它所指的地址没变,所以通过 interface{} 调用方法仍能修改原值。这点让很多人误以为 interface{} 是引用传递。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

177

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

225

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

336

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

207

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

388

2024.05.21

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

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

194

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

189

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

191

2025.06.17

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

1

2026.01.06

热门下载

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

精品课程

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

共101课时 | 8.1万人学习

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

共39课时 | 3.1万人学习

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

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