实际上 , 它将有些复杂 , 因为我们需要从allOverflow中删除旧的溢出桶 。而且它还会增加 hmap 的大小,因此也可能需要重新整理数据 。
最终官方在 hmap 中增加了overflow相关字段完成了上面的优化,这是具体的commit地址 。
下面看下具体是如何实现的,源码基于 go1.15,src/cmd/compile/internal/gc/reflect.go 中
通过注释可以看出,如果 map 中保存的键值都不包含指针(通过 Haspointers 判断),就使用一个 uintptr 类型代替 bucket 的指针用于溢出桶 overflow 字段,uintptr 类型在 GO 语言中就是个大小可以保存得下指针的整数,不是指针,就相当于实现了 将 bmap 标记为 noScan,GC 的时候就不会遍历完整个 map 了 。随着不断的学习,愈发感慨 GO 语言中很多模块设计得太精妙了 。
差不多说清楚了,能力有限,有不对的地方欢迎留言讨论,源码位置还是问的群里大佬 _
如何看待go语言泛型的最新设计?Go 由于不支持泛型而臭名昭著 , 但最近,泛型已接近成为现实 。Go 团队实施了一个看起来比较稳定go语言的数据结构书的设计草案,并且正以源到源翻译器原型go语言的数据结构书的形式获得关注 。本文讲述的是泛型的最新设计,以及如何自己尝试泛型 。
例子
FIFO Stack
假设你要创建一个先进先出堆栈 。没有泛型,你可能会这样实现:
type Stack []interface{}func (s Stack) Peek() interface{} {
return s[len(s)-1]
}
func (s *Stack) Pop() {
*s = (*s)[:
len(*s)-1]
}
func (s *Stack) Push(value interface{}) {
*s =
append(*s, value)
}
但是,这里存在一个问题:每当你 Peek 项时 , 都必须使用类型断言将其从 interface{} 转换为你需要的类型 。如果你的堆栈是 *MyObject 的堆栈,则意味着很多 s.Peek().(*MyObject)这样的代码 。这不仅让人眼花缭乱,而且还可能引发错误 。比如忘记 * 怎么办go语言的数据结构书?或者如果您输入错误的类型怎么办?s.Push(MyObject{})` 可以顺利编译,而且你可能不会发现到自己的错误,直到它影响到你的整个服务为止 。
通常 , 使用 interface{} 是相对危险的 。使用更多受限制的类型总是更安全 , 因为可以在编译时而不是运行时发现问题 。
泛型通过允许类型具有类型参数来解决此问题:
type Stack(type T) []Tfunc (s Stack(T)) Peek() T {
return s[len(s)-1]
}
func (s *Stack(T)) Pop() {
*s = (*s)[:
len(*s)-1]
}
func (s *Stack(T)) Push(value T) {
*s =
append(*s, value)
}
这会向 Stack 添加一个类型参数,从而完全不需要 interface{} 。现在,当你使用 Peek() 时,返回的值已经是原始类型 , 并且没有机会返回错误的值类型 。这种方式更安全,更容易使用 。(译注:就是看起来更丑陋,^-^)
此外,泛型代码通常更易于编译器优化,从而获得更好的性能(以二进制大小为代价) 。如果go语言的数据结构书我们对上面的非泛型代码和泛型代码进行基准测试,我们可以看到区别:
type MyObject struct {
X
int
}
var sink MyObjectfunc BenchmarkGo1(b *testing.B) {
for i := 0; ib.N; i++ {
var s Stack
s.Push(MyObject{})
s.Push(MyObject{})
s.Pop()
sink = s.Peek().(MyObject)
}
}
func BenchmarkGo2(b *testing.B) {
for i := 0; ib.N; i++ {
var s Stack(MyObject)
s.Push(MyObject{})
s.Push(MyObject{})
s.Pop()
sink = s.Peek()
}
}
结果:
BenchmarkGo1BenchmarkGo1-161283752887.0 ns/op48 B/op2 allocs/opBenchmarkGo2BenchmarkGo2-162840647941.9 ns/op24 B/op2 allocs/op
推荐阅读
- oracle新建表,Oracle新建表语句
- java代码保护,java受保护的方法
- chatgpt网页版打不开,potato chat网页版
- 搞怪的解谜手机游戏下载,搞怪解密的方法
- mysql怎么看密码 mysql如何查看用户密码
- oracle按时间段查询优化,oracle按时间戳查询
- 如何看待新媒体内容,你怎么看待新媒体的兴起和普及?
- c语言函数与结构体实验 c 结构体函数
- 软件查chatgpt,查重率用什么软件查