目录
golang 1.18版本后支持泛型编程。
# 什么是泛型
1. 泛型即开发过程中编写适用于所有类型的模板,只有在具体使用的时候才能确定其真正的类型
# 泛型的作用与应用场景
1. 增加代码的复用,从同类型的复用到不同类型的代码复用
2. 应用于不同类型间代码复用的场景,即不同类型需要写相同的处理逻辑时,最适合用泛型
# 泛型的利弊
1. 提高了代码复用率,提高了编程效率
2. 不同类型间代码复用,使得代码风格更加优雅
3. 增加了编译器的负担,降低了编译效率
# golang的泛型怎么使用
1. 泛型函数
2. 泛型类型
3. 泛型接口
4. 泛型结构体
5. 泛型receiver
# 泛型限制
1. 匿名结构体与匿名函数不支持泛型
2. 不支持类型断言
3. 不支持泛型方法,只能通过receiver来实现方法的泛型处理
4. ~后的类型必须为基本类型,不能为接口类型
【1】泛型写法
func SimpleCase() {
var a, b = 3, 4
var c, d float64 = 5.4, 6.3
fmt.Println("不使用泛型,数字比较:", getMaxNumInt(a, b))
fmt.Println("不使用泛型,数字比较:", getMaxNumFloat(c, d))
//由编译器推断输入的类型
fmt.Println("使用泛型,数字比较:", getMaxNum(a, b))
//显示指定传入的类型
fmt.Println("使用泛型,数字比较:", getMaxNum[float64](c, d))
}
func getMaxNumInt(a, b int) int {
if a > b {
return a
}
return b
}
func getMaxNumFloat(a, b float64) float64 {
if a > b {
return a
}
return b
}
//泛型函数定义,可以使用interface{}包裹防止加 * 时被当做乘法运算,也可以不包裹
func getMaxNum[T interface{ int | float64 }](a, b T) T {
if a > b {
return a
}
return b
}
【2】自定义泛型
type CusNumT interface {
// 支持 uint8 、int32 、 float64 与 int64及其衍生类型
// ~ 标识支持类型的衍生类型
// | 表示取并集
// 多行之间取交集
uint8 | int32 | float64 | ~int64
int32 | float64 | ~int64 | uint16
}
// MyInt64 为int64的衍生类型,具有基础类型int64的新类型,与int64是不同类型
type MyInt64 int64
// MyInt32 为 int32 的别名,与 int32 是同一类型
type MyInt32 = int32
func CusNumTCase() {
var a, b int32 = 3, 4
var a1, b1 MyInt32 = a, b
fmt.Println("自定义泛型,数字比较:", GetMaxCusNum(a, b))
fmt.Println("自定义泛型,数字比较:", GetMaxCusNum(a1, b1))
var c, d float64 = 5.4, 6.3
fmt.Println("自定义泛型,数字比较:", GetMaxCusNum(c, d))
var e, f int64 = 7, 8
var g, h MyInt64 = 7, 8
fmt.Println("自定义泛型,数字比较:", GetMaxCusNum(e, f))
fmt.Println("自定义泛型,数字比较:", GetMaxCusNum(g, h))
}
func GetMaxCusNum[T CusNumT](a, b T) T {
if a > b {
return a
}
return b
}
【3】内置泛型类型约束
//内置类型
func BuiltInCase() {
var a, b string = "abc", "efg"
fmt.Println("内置 comparable 泛型类型约束", getBuiltInComparable[string](a, b))
var c, d float64 = 100, 100
fmt.Println("内置 comparable 泛型类型约束", getBuiltInComparable(c, d))
var e = 100.123
var f = "你好"
printBuiltInAny(e)
printBuiltInAny(f)
}
func getBuiltInComparable[T comparable](a, b T) bool {
//comparable 类型,只支持 == != 两个操作
return a == b
}
func printBuiltInAny[T any](a T) {
fmt.Println("内置 any 泛型类型约束", a)
}
【4】泛型函数
package _case
import "fmt"
type user struct {
ID int64
Name string
Age uint8
}
type address struct {
ID int
Province, 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) {
for data := range ch {
fmt.Println(data)
}
}
func TTypeCase() {
userMp := make(map[int64]user, 0)
userMp[1] = user{1, "tom", 19}
userMp[2] = user{2, "jack", 20}
userList := mapToList[int64, user](userMp)
ch := make(chan user)
go myPrintln(ch)
for _, u := range userList {
ch <- u
}
addrMp := make(map[int64]address, 0)
addrMp[1] = address{1, "上海", "浦东"}
addrMp[2] = address{2, "上海", "闵行"}
addrList := mapToList[int64, address](addrMp)
ch1 := make(chan address)
go myPrintln(ch1)
for _, u := range addrList {
ch1 <- u
}
}
调用
package main
import (
"context"
"fmt"
"os"
"os/signal"
_case "project01/generic-T/case"
)
func main() {
_case.TTypeCase()
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
defer stop()
<-ctx.Done()
}
【5】泛型切片、集合、通道
// 泛型切片的定义
type List[T any] []T
// 泛型集合的定义
// 声明两个泛型 分别为K , V
type MapT[K comparable, V any] map[K]V
// 泛型通道的定义
type Chan[T any] chan T
func TTypeCase1() {
userMp := make(MapT[int64, user], 0)
userMp[1] = user{1, "tom", 19}
userMp[2] = user{2, "jack", 20}
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[int, address], 0)
addrMp[1] = address{1, "上海", "浦东"}
addrMp[2] = address{2, "上海", "闵行"}
var addrList List[address]
addrList = mapToList(addrMp)
ch1 := make(Chan[address])
go myPrintln(ch1)
for _, u := range addrList {
ch1 <- u
}
}
【6】泛型接口
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
Get() T
}
func (u user) Get() int64 {
return u.ID
}
func (addr address) Get() int {
return addr.ID
}
// 列表转集合
func listToMap[K comparable, T GetKey[K]](list []T) map[K]T {
mp := make(MapT[K, T], len(list))
for _, data := range list {
mp[data.Get()] = data
}
return mp
}
func InterfaceCase() {
userList := []GetKey[int64]{
user{1, "tom", 18},
user{2, "jack", 20},
}
addrList := []GetKey[int]{
address{1, "上海", "陆家嘴"},
address{2, "上海", "虹桥"},
}
userMp := listToMap[int64, GetKey[int64]](userList)
fmt.Println(userMp)
addrMp := listToMap[int, GetKey[int]](addrList)
fmt.Println(addrMp)
}
【7】泛型结构体
package _case
import "fmt"
//泛型结构体
type MyStruct[T interface{ *int | *string }] struct {
Name string
Data T
}
func (m MyStruct[T]) GetData() T {
return m.Data
}
func ReceiverCase() {
data := 18
myStruct := MyStruct[*int]{
Name: "lucy",
Data: &data,
}
data1 := myStruct.GetData()
fmt.Println(*data1)
str := "hello"
myStruct1 := MyStruct[*string]{
Name: "lucy",
Data: &str,
}
str1 := myStruct1.GetData()
fmt.Println(*str1)
}