Dominik Braun
万俊峰Kevin:我看了感觉文章非常简单易懂,就征求了作者批准,翻译进去给大家分享一下。
本文是对泛型的根本思维及其在 Go 中的实现的一个比拟容易了解的介绍,同时也是对围绕泛型的各种性能探讨的简略总结。首先,咱们来看看泛型所解决的外围问题。
问题
tree
type Node struct {
value interface{}
}
这在大多数状况下都很好用,但它也有一些毛病。
interface{}value
func (n Node) IsValid() bool {
switch n.value.(type) {
case int, float32, float64:
return true
default:
return false
}
}
这样并不可能在编译时限度类型,像下面这样的类型判断在许多 Go 库中都是很常见的做法。这里有 go-zero 我的项目中的例子。
int
number, ok := node.value.(int)
if !ok {
// ...
}
double := number * 2
interface{}
解决办法
T占位符类型
type Node[T] struct {
value T
}
T
TNodeT
n := Node[int]{
value: 5,
}
NodeNode[int]Tint
类型束缚
T
T
type Node[T any] struct {
value T
}
Tcomparable==
type Node[T comparable] struct {
value T
}
interface
type Numeric interface {
int | float32 | float64
}
Numeric
type Node[T Numeric] struct {
value T
}
重获类型平安
interface{}TTT
T
func (n Node[T]) Value() T {
return n.value
}
n.ValueTTTint
n := Node[int]{
value: 5,
}
double := n.Value() * 2
在编译时复原类型平安使 Go 代码更牢靠,更不容易出错。
泛型应用场景
Ian Lance Taylor
slicesmapschannelslinked listtree
Node
Read(r io.Reader)Read[T io.Reader](r T)
性能
要理解泛型的性能及其在 Go 中的实现,首先须要理解个别状况下实现泛型的两种最常见形式。
这是对各种性能的深入研究和围绕它们进行的探讨的简要介绍。你大概率不太须要关怀 Go 中泛型的性能。
虚构办法表
Virtual Method Table
Virtual Method Table
Virtual Method TableVirtual Method Table
单态化
Monomorphization
func max[T Numeric](a, b T) T {
// ...
}
larger := max(3, 5)
intmax
func maxInt(a, b int) int {
// ...
}
larger := maxInt(3, 5)
MonomorphizationVirtual Method Table
Go 的实现
这两种办法中哪一种最适宜 Go?疾速编译很重要,但运行时性能也很重要。为了满足这些要求,Go 团队决定在实现泛型时混合两种办法。
Monomorphizationintfloat64Node"值类型"
Virtual Method Table
论断
MonomorphizationVirtual Method Table
在性能探讨中常常被疏忽的是,所有这些益处和老本只波及到函数的调用。通常状况下,大部分的执行工夫是在函数外部应用的。调用办法的性能开销可能不会成为性能瓶颈,即便是这样,也要思考先优化函数实现,再思考调用开销。
更多浏览
Vicent Marti: Generics can make your Go code slower (PlanetScale)
Andy Arthur: Generics and Value Types in Golang (Dolthub)
Virtual method table (Wikipedia)
Monomorphization (Wikipedia)
Dynamic dispatch (Wikipedia)
对规范库的影响
不扭转规范库
Go 有一些对于通用包、函数和数据结构的提议:
constraintsmapsslicessort.SliceOfsync.PoolOf
对于 go-zero 泛型的打算
对 go-zero 反对用泛型改写,咱们持审慎态度,因为一旦应用泛型,那么 Go 版本必须从 1.15 降级到 1.18,很多用户的线上服务当初还未降级到最新版,所以 go-zero 的泛型改写会延后 Go 两三个版本,确保用户线上服务大部分曾经降级到 Go 1.18
go-zero
mr
https://github.com/kevwan/mapreduce
fxtemplate method
https://github.com/kevwan/stream
go-zero
我的项目地址
https://github.com/zeromicro/go-zero
go-zero
微信交换群
关注『微服务实际』公众号并点击 交换群 获取社区群二维码。
go-zero