https://go.dev/doc/tutorial/generics

和interface做下对比

显而易见比interace实现代码要少。

T 是 int或int32的其中之一的类型 用 | 表示或 。 其他类型不都行

any 表示任意类型,demo是指定了类型。

 1package main 
 2import "fmt"
 3
 4func Add[T int | int32 | float64](a, b T) T {
 5	return a + b
 6}
 7
 8func IAdd(a, b interface{}) interface{} {
 9	switch a.(type) {
10	case int:
11		return a.(int) + b.(int)
12	case int32:
13		return a.(int32) + b.(int32)
14	case float32:
15		return a.(float32) + b.(float32)
16	case float64:
17		return a.(float64) + b.(float64)
18	}
19	return nil
20}
21
22func main() {
23	fmt.Println(Add[int](1, 2))
24	fmt.Println(Add[float64](1.0, 2.1))
25	fmt.Println(Add(1.0, 2.1))
26	print(IAdd(1, 2).(int), "\n")
27}

快速使用泛型

先举个例子,遍历一个string 切片, 需要类型断言才能遍历

 1func TestInterface(t *testing.T) {
 2	var user = []string{"cr-mao", "lishuai"}
 3	PrintUser(user)
 4}
 5
 6func PrintUser(u interface{}) {
 7  //需要类型断言才能遍历
 8	for k, v := range u.([]string) {
 9		fmt.Println(k, v)
10	}
11}

或者改成这样,字符串切片改成interface切片

 1func TestSliceInterface(t *testing.T) {
 2	var user = []interface{}{"cr-mao", "lishuai"}
 3	PrintUser1(user)
 4}
 5
 6func PrintUser1(users []interface{}) {
 7	for k, v := range users {
 8		fmt.Println(k, v)
 9	}
10}

但是现在有了泛型,我们就可以这样了,不需要断言

 1func TestFanxing(t *testing.T) {
 2	var users = []string{"cr-mao", "lishuai"}
 3	PrintUser2(users)
 4}
 5
 6func PrintUser2[t any](users []t) {
 7	for k, v := range users {
 8		fmt.Println(k, v)
 9	}
10}

自定义类型约束

 1// 自定义类型约束的能力
 2type Number interface {
 3	int | float32 | float64 | int32
 4}
 5
 6func min[V Number](a, b V) V {
 7	if a < b {
 8		return a
 9	} else {
10		return b
11	}
12}

内置的约束

go get golang.org/x/exp/constraints

 1
 2package main
 3
 4import "fmt"
 5
 6import (
 7	"golang.org/x/exp/constraints"
 8)
 9
10func min[V constraints.Ordered](a, b V) V {
11  if a < b {
12    return a
13  } else {
14    return b
15  }
16}

实体类

结构体中指定类型

 1type Man struct {
 2}
 3
 4type Woman struct {
 5}
 6
 7type Company[T Man | Woman] struct {
 8	Name string
 9	CEO  T
10}
11
12//类型嵌套
13type WowStruct[T string | int, S []T] struct {
14    A T
15    B S
16}
17
18func main(){
19    var c1 = Company[Man]{
20            Name: "cr-mao",
21            CEO: Man{},
22    }
23    fmt.Println(c1)
24	var w1 = WowStruct[string, []string]{
25        A: "woman",
26        B: []string{"a", "b", "c"},
27    }
28    fmt.Println(w1)
29}

定义个用户模型 Id是泛型 ,UserModel加入泛型标志

 1type UserModel[t any] struct {
 2	Id   t
 3	Name string
 4}
 5
 6func TestStuctFanxing(t *testing.T) {
 7	u := &UserModel[int]{
 8		Id:   123,
 9		Name: "cr-mao",
10	}
11	u1 := &UserModel[string]{
12		Id:   "123",
13		Name: "cr-mao",
14	}
15	fmt.Println(u, u1)
16}

定义个用户模型Id,Name都是泛型,UserModel加入泛型标志

 1type UserModel1[t any, t1 any] struct {
 2	Id   t
 3	Name t1
 4}
 5
 6func TestStuctFanxing1(t *testing.T) {
 7	u := &UserModel1[int, string]{
 8		Id:   123,
 9		Name: "cr-mao",
10	}
11	u1 := &UserModel1[string, string]{
12		Id:   "123",
13		Name: "cr-mao",
14	}
15	fmt.Println(u, u1)
16}

构造函数

UserModel加入泛型标志,使用的时候也要加入泛型标志

 1type UserModel[t any] struct {
 2	Id   t
 3	Name string
 4}
 5
 6func NewUserModel[t any](id t) *UserModel[t] {
 7	return &UserModel[t]{
 8		Id:   id,
 9		Name: "crmao",
10	}
11}
12
13func TestConstruct(t *testing.T) {
14	u := NewUserModel[int](123)
15	fmt.Println(u)
16}
17
18// -----------------------
19
20//2个泛型
21type UserModel1[t any, t1 any] struct {
22	Id   t
23	Name t1
24}
25//传入2个泛型参数
26func NewUserModel1[t any, t1 any](id t, name t1) *UserModel1[t, t1] {
27	return &UserModel1[t, t1]{
28		Id:   id,
29		Name: name,
30	}
31}
32func TestStuctFanxing2(t *testing.T) {
33	fmt.Println(NewUserModel1[int, string](123, "cr-mao"))
34}

map泛型

 1package main
 2
 3import "fmt"
 4
 5type myMap[Key string | int, Value string | int] map[Key]Value
 6
 7func main(){
 8	var m1 = make(myMap[string, string], 1)
 9	m1["aa"] = "bb"
10
11	var m2 = make(myMap[string, int], 0)
12	m2["aa"] = 1
13	fmt.Println(m1)
14	fmt.Println(m2)
15}

chan泛型

 1package main
 2import "fmt"
 3
 4type MyChannel[T int | string] chan T
 5
 6func main(){
 7    var chan1 = make(MyChannel[int])
 8    go func() {
 9        chan1 <- 1
10    }()
11    fmt.Println(<-chan1)
12}

常见错误用法

  • 类型参数不能单独使用
    • type CommonType[T int | string] T (错误)
    • type CommonType[T int | string] []T 这种可以
  • 指针类型
    • type CommonType[T *int | string] []T (*int 会当作表达式 乘号)
    • type CommonType[T interface{ *int } | string] []T (包一层interface{})
  • 匿名结构体不支持泛型
  • 泛型不支持switch判断
  • 匿名函数不支持泛型