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