什么是泛型
泛型即开发过程中编写适用于所有类型的模板,只有在具体使用的时候才能确定真正的类型
泛型的作用与应用场景
- 增加代码的复用,从同类型的复用到不同类型的代码复用
- 应用于不同类型间代码复用的场景,即不同类型需要写相同的处理逻辑时,最适合用泛型
泛型的利弊
- 提高了代码复用率,提高了编程效率
- 不同类型间代码复用,使代码风格更加优雅
- 增加了编译器的负担,降低了编译效率
golang泛型的使用
泛型函数
泛型函数的快速入门
func getMaxNum[T int | float32 | float32](a, b T) T {
if a > b {
return a
}
return b
}
使用接口定义泛型约束
func getMaxNum[T CusNumT](a, b T) T {
if a > b {
return a
}
return b
}
type CusNumT interface { //定义泛型类型约束
//支持uint8 | float32 | float64 | ~int64及其衍生类型
//~ 表示支持类型的衍生类型
// 多行之间取并集
uint8 | float32 | float64 | ~int64
int32 | float64 | ~int64 | uint16
}
// MyInt64 为int64的衍生类型,是具有基础类型int64的新类型, 与int64不同类型
type MyInt64 int64
内置类型
any代表任意类型,comparable 类型, 只支持 == != 两个操作
// BuiltInCase 内置类型
func BuiltInCase() {
var a, b string = "abc", "123"
fmt.Println("内置 comparable 泛型类型约束", getBuiltInComparable(a, b))
var c, d float64 = 100, 100
fmt.Println("内置 comparable 泛型类型约束", getBuiltInComparable(c, d))
}
func getBuiltInComparable[T comparable](a, b T) bool {
//comparable 类型, 只支持 == != 两个操作
if a == b {
return true
}
return false
}
泛型类型
package _case
import (
"fmt"
)
type user struct {
ID int64
Name string
Age uint8
}
type address struct {
ID int
Province string
City string
}
// 集合转列表
func mapToList[k comparable, T any](mp map[k]T) []T {
list := make([]T, len(mp))
var i int
for _, data := range mp {
list[i] = data
i++
}
return list
}
func myPrintln[T any](ch chan T) { //h是一个通道(channel),其元素类型为T
for data := range ch {
fmt.Println(data)
}
}
// 泛型切片的定义
type List[T any] []T
// 泛型集合的定义
type MapT[k comparable, v any] map[k]v
// 泛型通道的定义
type Chan[T any] chan T
func TTypeCase() {
userMp := make(MapT[int64, user], 0)
userMp[1] = user{
ID: 1,
Name: "jack",
Age: 18,
}
userMp[2] = user{
ID: 2,
Name: "Tom",
Age: 19,
}
var userList List[user]
userList = mapToList[int64, user](userMp)
ch := make(Chan[user])
go myPrintln(ch)
for _, u := range userList {
ch <- u
}
addrMp := make(MapT[int64, address], 0)
addrMp[1] = address{
ID: 1,
Province: "四川",
City: "中国",
}
addrMp[2] = address{
ID: 2,
Province: "新疆",
City: "中国",
}
var addrList []address
addrList = mapToList[int64, address](addrMp)
ch1 := make(Chan[address])
go myPrintln(ch1)
for _, a := range addrList {
ch1 <- a
}
}
泛型接口
GetKey实现了any接口即 实现interface{}空接口,可以被任意类型调用
Get为其实现的接口
// 泛型接口
type GetKey[T comparable] interface {
any //即为 interface{} 继承了空接口的特性
Get() T //传入的泛型为 comparable
}
其中T GetKey可以被看作实现了GetKey中Get接口的类型,所以实现了Get()接口,另一个接口又为空接口 就可以使用GetKey
// 列表转集合
func listToMap[k comparable, T GetKey[k]](list []T) map[k]T { //T 可以被看作实现GetKey中Get()接口的类型
mp := make(MapT[k, T], len(list))
for _, data := range list {
mp[data.Get()] = data //data.Get 是传入的对象调用其实现的Get方法
}
return mp
}
func (u user) Get() int64 { //user 实现Get方法
return u.ID
}
func (addr address) Get() int { //address 实现Get方法
return addr.ID
}
完整代码
package _case
import "fmt"
// 基本接口,可用于变量的定义
type ToString interface {
String() string
}
func (u user) String() string {
return fmt.Sprintf("ID: %d, Name: %s, Age: %d", u.ID, u.Name, u.Age)
}
func (addr address) String() string {
return fmt.Sprintf("ID: %d, Province: %s, City: %s", addr.ID, addr.Province, addr.City)
}
// 泛型接口
type GetKey[T comparable] interface {
any //即为 interface{} 继承了空接口的特性
Get() T //传入的泛型为 comparable
}
func (u user) Get() int64 { //user 实现Get方法
return u.ID
}
func (addr address) Get() int { //address 实现Get方法
return addr.ID
}
// 列表转集合
func listToMap[k comparable, T GetKey[k]](list []T) map[k]T { //T 可以被看作实现GetKey中Get()接口的类型
mp := make(MapT[k, T], len(list))
for _, data := range list {
mp[data.Get()] = data //data.Get 是传入的对象调用其实现的Get方法
}
return mp
}
func InterfaceCase() {
userList := []GetKey[int64]{ //存储实现了 Get() 方法且返回类型为 int64 的类型的集合
user{ID: 1, Name: "jack", Age: 18},
user{ID: 2, Name: "Tom", Age: 19},
}
addrList := []GetKey[int]{
address{ID: 1, Province: "四川", City: "中国"},
address{ID: 2, Province: "新疆", City: "中国"},
}
userMp := listToMap[int64, GetKey[int64]](userList) //将实现GetKey接口返回值为int64的数据类型转为集合
addrMp := listToMap[int, GetKey[int]](addrList)
fmt.Println(userMp)
fmt.Println(addrMp)
}
泛型结构体
注意事项:在泛型中使用指针定义会被当做表达式,需要使用interface来定义指针
// MyStruct 泛型结构体
type MyStruct[T interface{ *int | *string }] struct { //在结构体中泛型使用指针定义会被看成常量表达式,使用interface
Name string
Data T
}
泛型receiver
// GetData 泛型receiver
func (myStruct MyStruct[T]) GetData() T {
return myStruct.Data
}
泛型限制
- 匿名结构体与匿名函数不支持泛型
- 不支持类型断言
- 不支持泛型方法,只能通过receiver来实现方法的泛型处理
- ~后的类型必须为基本类型,不能为接口类型