Golang 哈希表作为函数参数底层原理解析(二)

Golang 哈希表作为函数传参解惑

一、Golang所有变量的参数传递都是值传递

2、哈希表
这次我们讲哈希表作为函数参数的底层原理分析,首先我们看一下哈希表的结构体定义
在这里插入图片描述
在Golang中,哈希表是数组+单链表实现的,单链表节点保存了8个key-value和对应键的高八位,方便快速查找。这里简单作一下结构体中关键变量的含义,buckets是哈希表数据的指针变量,oldbuckets是旧哈希表数据的指针变量,保存新、旧哈希表指针变量的作用是为了哈希表渐进式扩容的。

我们来看一段代码,哈希表作为函数传递时,在函数内发生了扩容行为,主函数能否感受到哈希表的变化,然后为什么一定能感受到变化,而切片有些情况下不能

func main() {

	//m := make([]int, 0)
	hashMap := make(map[int]int, 0)

	//fmt.Printf("Map address1: %p\n", &m)
	fmt.Printf("Slice address1: %p\n", &hashMap)
	//test1(m)
	testMap(hashMap)

	fmt.Println(hashMap)

	fmt.Printf("Slice address4: %p\n", &hashMap)

}
func testMap(m map[int]int) {
	fmt.Printf("Map address3: %p\n", &m)
	for i := 1; i < 2; i++ {
		m[i] = i
	}
	fmt.Printf("Map address3: %p\n", &m)
}

输出结果为

Map address1: 0xc0000ac018//主函数参数的地址
Map address3: 0xc0000ac028//依然是行参
Map address3: 0xc0000ac028//行参扩容后
map[1:1]//主函数能感受到testMap函数对哈希表的添加行为
Map address4: 0xc0000ac018//主函数参数的地址

可以看到,Golang的参数传递都是值传递,在testMap函数中,哈希表发生了扩容行为,但是哈希表并不像切片一样,主函数的哈希表依然看到了添加行为

这是为什么?

前面我们说了,buckets是哈希表数据的指针变量。形参m内的buckets是指针变量,指针作为参数传递的时候,其实是复制的地址,也就是原哈希表buckets的地址。

所以在形参上对哈希表的buckets添加元素,其实就是对原哈希表buckets进行添加元素

不过你可能会疑惑,初始化时候哈希表大小是0,添加元素不是会发生扩容行为吗,发生了扩容行为,行参map的buckets应该是指向新的桶,和原map的buckets不是同一个啊,为什么原map还能看到。

这涉及到哈希表复杂的扩容触发机制和相应的扩容行为扩容触发机制可以是装载因子或者是溢出桶数量的阈值扩容行为渐进式扩容的。渐进式扩容就是不马上把旧桶数据删掉,而是通过前面说的oldbuckets引用着先,慢慢把oldbuckets的数据引到新buckets中,

那为什么,行参map的buckets应该是指向新的桶,和原map的buckets不是同一个,为什么原map还能看到。

哈哈这个我也不知道,因为具体哈希表扩容行为我目前还不知道怎么控制(此处笑死)。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值