go 1.18 泛型初体验

作者 2022年01月04日 15:26 阅读 1434

go 1.18 泛型初体验

go.1.18beta 版发布,众所周知这个 go.1.18 版本会默认启用 go 泛型。这个版本也号称 go 最大的版本改动。

初识 golang 的泛型

我们写一个 demo 来看看 go 的泛型是长啥样

package main

import (
    "fmt"
)

type OrderTypes interface {
    ~int | ~float32 | ~string
}

func max[T OrderTypes](x, y T) T {
    if x > y {
        return x
    }
    return y
}

func main() {
    fmt.Println(max(1, 11), max("abc", "eff"))
}

ok run 一下代码

$ go run main.go
11 eff

~int | ~float32 | ~string我们看到了新的语法,~是新的操作符,主要用来做类型约束使用, ~int代表类型约束为int类型,~int | ~float32 | ~string则代表约束为 int 或者 float32 或者 string。上面额例子中,这三个类型刚好是可以比较的能进行 ">" 操作的。

当然上面的代码是演示用的,在真正的项目中我们应该使用标准constraints提供的Ordered来做约束。

import (
    "constraints"
)
func max[T constraints.Ordered](x, y T) T {
    if x > y {
        return x
    }
    return y
}

constraints标准库定义了一下常用的类型约束,如Ordered,Signed,Unsigned,Integer,Float。

提高生产力的泛型

我们通过下面的例子来看看泛型,如何提高我们的生产力。我们将为所有slice类型添加三件套map,reduce,filter

func Map[Elem1, Elem2 any](s []Elem1, f func(Elem1) Elem2) []Elem2 {
    r := make([]Elem2, len(s))
    for i, v := range s {
        r[i] = f(v)
    }
    return r
}

func Reduce[Elem1, Elem2 any](s []Elem1, initializer Elem2, f func(Elem2, Elem1) Elem2) Elem2 {
    r := initializer
    for _, v := range s {
        r = f(r, v)
    }
    return r
}

func Filter[Elem any](s []Elem, f func(Elem) bool) []Elem {
    var r []Elem
    for _, v := range s {
        if f(v) {
            r = append(r, v)
        }
    }
    return r
}

func Silce() {
    sliceA := []int{3, 99, 31, 63}
    //通过sliceA 生成sliceB
    sliceB := Map(sliceA, func(e int) float32 {
        return float32(e) + 1.3
    })
    fmt.Println(sliceB)
    //找最大值
    max := Reduce(sliceB, 0.0, func(a, b float32) float32 {
        if a > b {
            return a
        }
        return b
    })
    fmt.Println(max)
    //过滤sliceA中大于30的组成新的slice
    sliceC := Filter(sliceA, func(e int) bool {
        if e > 30 {
            return true
        }
        return false
    })
    fmt.Println(sliceC)
}

func main() {
    Silce()
}
$ go run main.go 
[4.3 100.3 32.3 64.3]
100.3
[99 31 63]

带泛型的struct

接下来我们看一下带泛型的struct

//定义的时候需要加约束
type Student[T constraints.Unsigned] struct {
    Age T
}

//后续struct方法编写的时候 约束就不能写了
func (s *Student[T]) GetAge() T {
    return s.Age
}

我们初始化带泛型的结构体

age := uint(3)
s := &Student[uint]{Age: age}
fmt.Println(s.GetAge()) //3
s1 := &Student[uint16]{Age: uint16(age)}
fmt.Println(s1.GetAge()) //3

总结

go 的泛型目前还没有官方推荐的最佳实践,标准库的代码也基本没改成泛型。但总归走出支持泛型这一步,后续丰富标准库应该是后面版本的事情了。再看go2代码的时候发现一个有意思的东西--orderedmap。感兴趣的同学可以去看看。

原文链接:https://gocn.vip/topics/20855

发表评论