最新go1.18泛型教程,看完都懂了
2022.03

go1.18泛型全部教程

1. 声明一个泛型函数

package main

import "fmt"

func printslice[T any](s []T){
	for _,v := range s{
		fmt.Printf("%v\n",v)
	}
}


func main(){
	printslice[int]([]int{66,77,88,99,100})
	printslice[float64]([]float64{1.1,2.2,5.5})
	printslice[string]([]string{"烤鸡","烤鸭","烤鱼","烤面筋"})

	//省略显示类型
	printslice([]int64{55,44,33,22,11})

}

[T any]参数的类型,意思是该函数支持任何T类型;

多个泛型参数语法:

[T, M any]
[T any, M any]
[T any, M comparable]

在调用这个泛型函数的时候,可以显示指定类型参数,

如: printsliceint

也可以省略显示类型

比如 printslice([]int64(55,44,33,22,11))

2. 声明一个泛型切片

带有类型参数的类型被叫做泛型类型。下面定义一个底层类型为切片类型的新类型 vector。它是可以存储任何类型的的切片。要使用泛型类型,要先对其进行实例化,就是给类型参数指定一个实参。

package main
import "fmt"

type vector[T any][]T

func printslice[T any](s []T){
	for _,v := range s{
		fmt.Printf("%v",v)
	}
}

func main(){
	v:=vector[int]{58,1881}
	printslice(v)
	v2:=vector[string]{"烤鸡","烤鸭","烤鱼","烤面筋"}
	printslice(v2)
}

3. 声明一个泛型map

package main
import "fmt"

type M[K string, V any] map[K]V   //这里的K不支持any ,由于底层map不支持,所以使用string

func main() {
	m1 := M[string, int]{"key": 1}
	m1["key"] = 2

	m2 := M[string, string]{"key": "value"}
	m2["key"] = "new value"
	fmt.Println(m1, m2)

}

4. 声明一个泛型通道


package main

import "fmt"

type C[T any] chan T

func main() {
	c1 := make(C[int], 10)
	c1 <- 1
	c1 <- 2

	c2 := make(C[string], 10)
	c2 <- "hello"
	c2 <- "world"

	fmt.Println(<-c1, <-c2)

}

5. 泛型约束

使用interface中规定的类型约束泛型函数的参数

package main

import "fmt"

type NumStr interface {
	Num | Str
}
type Num interface {
	~int | ~int8 | ~int16| ~int32| ~int64| ~uint| ~ uint8| ~ uint16| ~ uint32| ~uint64| ~ uintptr| ~ float32| ~ float64| ~ complex64| ~ complex128
}
type Str interface {
	string
}

func add[T NumStr](a,b T) T {
	return a + b
}

func main(){
	fmt.Println(add(3,4))
	fmt.Println(add("hello","world"))
}

上面的 NumStr,新增了类型列表表达式,它是对类型参数进行约束。

使用 | 表示取并集

如果传入参数不在集合限制范围内,就会报错。

使用interface中规定的方法来约束泛型的参数

package main

import (
	"fmt"
	"strconv"
)

type Price int

func (i Price) String() string {
	return strconv.Itoa(int(i))
}

type Price2 string

func (i Price2) String() string {
	return string(i)
}

type ShowPrice interface {
	String() string
	~int | ~string
}

func ShowPriceList[T ShowPrice](s []T) (ret []string) {
	for _, v := range s {
		ret = append(ret, v.String())
	}
	return
}

func main() {
	fmt.Println(ShowPriceList([]Price{1, 2}))
	fmt.Println(ShowPriceList([]Price2{"a", "b"}))
}

使用interface中规定的方法和类型来双重约束泛型的参数

package main

import (
	"fmt"
	"strconv"
)

type Price int

type ShowPrice interface {
	String() string
	int | string
}

func (i Price) String() string {
	return strconv.Itoa(int(i))
}

func ShowPriceList[T ShowPrice](s []T) (ret []string) {
	for _, v := range s {
		ret = append(ret, v.String())
	}
	return
}

func main() {
	fmt.Println(ShowPriceList([]Price{1, 2}))
}

//传入浮点参数,就会因为不是约束类型而报错

使用泛型自带comparable约束,判断比较

package main

import (
	"fmt"
)

func findFunc[T comparable](a []T, v T) int {
	for i, e := range a {
		if e == v {
			return i
		}
	}
	return -1
}

func main() {
	fmt.Println(findFunc([]int{1, 2, 3, 4, 5, 6}, 5))
	fmt.Println(findFunc([]string{"烤鸡", "烤鸭", "烤鱼", "烤面筋"}, "烤面筋"))
}

comparable 的约束类型支持整数 和字符,自定义结构体,也可以嵌套在自定义约束中

type ShowPrice interface {	
	int | string | comparable 
}