Go中slice和map引用传递误区

背景

关于slice和map是指传递还是引用传递,很多文章都分析得模棱两可,其实在Go中只有值传递,但是很多情况下是因为分不清slice和map的底层实现,所以导致很多人在这一块产生疑惑,下面通过代码案例分析slice和map到底是值传递还是引用传递。

案例分析

go 复制代码
func main() {
	list := make([]int, 10)
	fmt.Printf("list addr:%p\n", list)
	fmt.Println("list size:", len(list))
	listExpand(list)
	fmt.Println("expand list size:", len(list))
	m := make(map[int]int, 0)
	fmt.Printf("map addr:%p\n", m)
	fmt.Println("map size:", len(m))
	mapExpand(m)
	fmt.Println("expand size:", len(m))
}

func mapExpand(m map[int]int) {
	for i := range 10 {
		m[i] = i
	}
	fmt.Printf("expand map addr:%p\n", m)
}

func listExpand(list []int) {
	for i := range 10 {
		list = append(list, i)
	}
	fmt.Printf("expand list addr:%p\n", list)
}

上面代码的输出结果:

go 复制代码
list addr:0xc000010500
list size: 10
expand list addr:0xc0000220a0
expand list size: 10
map addr:0xc00001e180
map size: 0
expand map addr:0xc00001e180
expand size: 10

可以清楚的看到,都没有使用指针的情况下,两者的结果都不一样,map在扩容前后都是同一个内存地址,但是slice在没扩容都不为同一个内存地址。

可能会更疑惑了,这结果是想说明,map是引用传递,slice是值传递吗?

在Go的1.8版本源码中

hashmap的make实现如下:

可以清楚的看到,通过make创建的map其实返回的是hamp结构体的指针。

slice的make实现如下:

可以清楚的看到,通过make创建的slice其实返回的是slice的结构体,并不是指针。

所以,结论很清晰了,其实Go中只有值传递,因为各个引用类型底层实现的不同导致的结果不一致,因为创建map返回的是指针,所以传递map时,扩容了也不会导致和预期不一样的结果;而slice的创建返回的是结构体,如果扩容了,则会导致底层数组的变化,不一定是预期的结果。

相关推荐
kite01216 小时前
Gin + Zap 日志:构建高性能、结构化的应用日志系统
golang·gin·log·zap
OxYGC7 小时前
[玩转GoLang] 5分钟整合Gin / Gorm框架入门
开发语言·golang·gin
向上的车轮10 小时前
基于go语言的云原生TodoList Demo 项目,验证云原生核心特性
开发语言·云原生·golang
360智汇云11 小时前
k8s交互桥梁:走进Client-Go
golang·kubernetes·交互
qq_1728055911 小时前
Go 装饰器模式学习文档
学习·golang·装饰器模式
秦禹辰13 小时前
宝塔面板安装MySQL数据库并通过内网穿透工具实现公网远程访问
开发语言·后端·golang
chen_ever14 小时前
golang之go modules
开发语言·后端·golang
今天头发还在吗16 小时前
【Go】:mac 环境下GoFrame安装开发工具 gf-cli——gf_darwin_arm64
macos·golang·go·gf-cli
是誰萆微了承諾1 天前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
ifanatic1 天前
[每周一更]-(第159期):Go 工程师视角:容器化技术(Docker/Kubernetes)与CI/CD流程的应用场景
docker·golang·kubernetes