go 1.18 泛型初體驗

wida發表於2021-12-16

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。感興趣的同學可以去看看。

更多原創文章乾貨分享,請關注公眾號
  • go 1.18 泛型初體驗
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章