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判断
- 匿名函数不支持泛型