golang泛型介绍

时间:2024-10-10 19:17:57

什么是泛型

首先来说说什么是泛型,泛型其实是一个很宽泛的概念。本文中的泛型特指计算机编程语言中的泛型, 即编程语言中的函数,方法,类定义等与特定的类型参数无关,相关的函数,方法和类的实例化是根据具体的调用参数来进行。泛型是和编译紧密相关的技术,尤其是针对 golang 这种静态类型的语言来说,更是如此。

为什么要实现泛型

作为一种提高编程效能的基本范式,目前市面上主流的编程语言都已经早早支持了泛型,比如 C++ 的 template, Java 的类型擦除技术等,其主要目的都是为了最大限度的避免重复代码,利用编译器来做类型检查,避免额外的装箱/拆箱等操作,来提高程序的性能。泛型最常用的地方就是集合类库,使得集合类针对不同的类型能够复用,并且最大化开发者的费效比,减少维护成本。

泛型可以为我们提供强大的构建块,让我们可以更轻松地共享代码和构建程序。泛型编程意味着编写函数和数据结构,其中一些类型留待以后指定。例如,我们可以编写一个对某种任意数据类型的切片进行操作的函数,其中实际数据类型仅在调用该函数时指定。或者,您可以定义存储任何类型值的数据结构,在创建数据结构的实例时指定要存储的实际类型。

Golang 泛型现状

go1.17之前,社区之前也有很多的努力和尝试,包括各种泛型提案和实现方式,但最后都被否决了。

Golang 核心作者给出的解释是泛型并不是不可或缺的特性。属于重要但不紧急,应该把精力集中在更重要的事情上,例如 GC 的延迟优化,编译器自举等。

go1.17中接受了社区的提议,具体细节在这/golang/go/issues/43651

go1.18beta 于 2021年12月15日发布,引入了泛型。1.18正式版本计划2022年2月发布。

go 1.18beta1是第一个包含Go对使用参数化类型的泛型代码的新支持。从Go 1 发布以来,泛型是Go最重要的变化,也是版本之后给你带来的最大的单一语言更改。

golang 泛型示例

环境准备

安装go1.18beta1,下载地址: /dl/。

安装后同步设置环境变量 GOROOT,GOBIN。

通过内置的约束来实现

使用any约束,实现一个简单的函数:

func Print[T any](s []T) {
       for _, v := range s {
              (v)
        }
 }

这里的[T any]即为类型参数,意思是该函数支持任何类型的 slice 。但是在调用该函数的时候,需要显式指定类型参数类型。类型在调用出需要显式指定,以便编译器可以推断出实际的类型。

Print([]string{"Hello, ", "World\n"})

显式指定类型调用:

Print[string]([]string{"One, ", "Two\n"})

使用 comparable 约束类型。 comparable 是一个编译器内置的特定的扩展接口类型,该类型必须支持“==“ 方法。
使用comparable约束实现Sum:

func SumIntsOrFloats[K comparable, V int | float64](m map[K]V) V {
    var s V
    for _, v := range m {
        s += v
    }
    return s
}

对其调用:

    ints := map[string]int{
        "first":  34,
        "second": 12,
    }

    floats := map[string]float64{
        "first":  35.98,