go语言之泛型
什么是泛型?
泛型可以理解为在编程过程中,定义的函数、方法时不需要指定类型,类型根据具体的调用参数来指定
1、下面例子定义函数,参数为空接口切片,调用函函数,遍历切片,如图:

执行结果如下:
[root@VM-12-12-centos gong]# go run fan.go
# command-line-arguments
./fan.go:13:6: cannot use []string{…} (value of type []string) as type []interface{} in argument to fan
从上面看出,执行结果出错,原因是虽然空接口(interface{})可以接受任何类型的数据,但是在和切片和映射配合的时候,无法将[]T转换为[]interface{}也不能将map[string]T转换为map[string]interface{}
使用泛型
1、重新修改上面的例子,声明一个泛型函数,如图:

- 第6行:在函数名fan和括号中间加了一对中括号[T any],里面参数为T,类型为any,表示支持任意参数,后面的函数参数s的类型则为[]T,这个T就是前面的中括号中的T,表示类型,注意:中括号里的参数不一定为T,写A也行写B也行,但是类型必须写any,否则报错,any为自带关键字
- 13-15行:调用函数,12、13行中函数名fan后写了一对中括号,括号中为要传递的类型,对应的就是any的值,此中括号可写可不写,15行中就省略了,没有写
执行结果如下:

any可以看做interface{}的别名
2、声明一个泛型切片,如图:

- 第6行:自定义类型,名字为fans,类型为切片,并使用了泛型
- 15、18行:实例化变量的时候,需要指定类型,也就是fans后面需要加上[int]才可以
运行结果如下:

3、声明一个泛型通道,如图:

运行结果如下:

4、声明一个泛型map,如图:

- 第6行:定义map类型变量fans中k的类型为string,v的类型使用泛型any
- 13、16行:实例化变量fans,指定泛型类型以及map的k和v
运行结果如下:

如果将第6行和第9行中的string也改为any会怎么样?如图:

运行结果如下:

报错内容为缺少可比较约束,为什么呢?因为golang泛型对于map的key有如下约束:
- key的类型必须是可以比较的,比较运算符为==和!=
- key的类型不能是function、map、slice(这几个不可比较)
- 对于interface类型,其动态类型必须可进行比较
可比较的类型有:布尔、整数、浮点、字符串、指针、channel、interface、complex,以及他们组成的结构体、数组。比较是==和!=比较,不涉及大小
不可比较类型有: function、map、slice,以及他们组成的结构体和数组。比较是==和!=比较,不涉及大小
泛型约束
泛型约束指的是约束泛型所能接受的数据类型,更直白的说就是这个 T 可以指代的数据类型
三个特殊的 泛型约束
- any:任何数据类型
- comparable:可以经行比较的数据类型(==, ≠)
- Ordered:可以进行大小判断的数据类型(<, >, ≤, ≥)
1、下面例子使用interface中规定的类型约束,如图:

- 第8行:定义comp接口,此接口中定义的约束类型只能为int 、string、int16三种
- 第9行:此种写法表示一个类型集,定义泛型的时候泛型种类必须属于其中某一种
- 第6行和第13行:使用comp接口中的类型

2、修改第一步中代码,添加自定义类型,调用时候指定自定义类型,如图:

- 第6行:自定义变量SelfInt,底层的类型为int16
- 第21行:实例化变量fmap时,传递类型SelfInt
执行结果报错如下:
./fan.go:23:5: SelfInt does not implement comp (possibly missing ~ for int16 in constraint comp)
从上述错误看出,报错原因说是int16类型缺少~,如果不加~,只有int16,那么表示传递的类型必须为int16,但是如果加了~,那么传递的类型可以是int16的所有类型的集合,SelfInt的底层是int16,因此如果要传递SelfInt,需要在int16前面加上~
修改上述代码,将int16改为~int16,再次执行打印结果即可,如图:

注意:建议将int、string这些前面都加上~,以防出错
附加:
1、还可以将上述的类型集分开在多个interface中写,如图:

2、方法不支持泛型,下图中写法就是错误的,如图:

上图中的[T any]写的位置是不对的,因为方法是不支持使用泛型,改造代码如下:

改造后的方法中虽然也有泛型的存在,但是这个泛型依赖的是上面结构体而存在,不是依赖于person()方法存在的,因此改造后的泛型是正确的,执行结果如下:

泛型和接口
type abc interface {
hello()string
}
type def interface{
~int | ~string
}
官方给出的说明为:
- 只有方法的接口叫做基本接口(Basic Interface)
- 包含类型约束的接口叫做一般接口(General Interface)—无论是否包含方法
3、使用泛型自带的comparable进行约束,如图:

上图中调用函数,遍历切片a,遍历的值与传递的变量b进行比较,如果相等则返回切片元素对应的索引,否则返回-1



