8、泛型

2022年3月15日,争议非常大但同时也备受期待的泛型终于伴随着Go1.18发布了。

Go 是一种静态类型编程语言,这意味着在编译时会检查变量和参数的类型。内置类型(map、slice、channel)和内置函数(如 len、cap 或 make)能够接收和返回不同具体类型的值,但在 Go 1.18 之前,用户定义的 Go 类型和函数不能如此。

使用前提

go version >= 1.18

没有泛型

例如

// 比较int类型
func compareMaxInt(a, b int) int {
	if a > b {
		return a
	}
	return b
}
// 比较float64类型
func compareMaxFloat(a, b float64) float64 {
	if a > b {
		return a
	}
	return b
}

有泛型

// 比较int或float64类型
func compareMax[T int | float64](a, b T) T{
	if a > b {
		return a
	}
	return b
}

泛型的定义

泛型函数

只需要在函数名后面使用中括号[]声明泛型名称,以及泛型允许出现的类型

// 定义泛型函数
func compareMax[T int | float64](a, b T) T{
	if a > b {
		return a
	}
	return b
}
//调用
func main() {
	// 自动类型推导
	compareMax(10, 20)
	// 指定类型
	compareMax[float64](10, 20)
}

泛型类型

自定义

用于泛型类型过多,或者该泛型类型在多处使用,定义方法类似于接口

// Num 自定义泛型类
type Num interface {
	int | float64 | float32 | rune
}

func compare[B Num](a, b B) B {
	if a > b {
		return a
	}
	return b
}

内置

any: 表示go里面所有的内置基本类型,等价于interface{}

comparable: 表示go里面所有内置的可比较类型:int、uint、float、bool、struct、指针等一切可以比较的类型,只可以使用==!=进行比较

func equal(a, b comparable) bool {
	return a == b
}

泛型结构体

package main

import "fmt"

type Student[K string | []byte, V int | float64] struct {
	id    int
	name  K
	score V
}

func main() {
	s1 := Student[string, int]{1, "lucy", 18}
	s2 := Student[[]byte, float64]{1, []byte("lucy"), 18.5}
	fmt.Println(s1, s2)
}

~符号

为了支持新定义的类型对其底层类型符合的方便使用,golang增加了新的~字符,意思是如果底层类型int,就可以正常进行泛型的实例化。

package main

type Num interface {
	int | float64
}

func equal[T Num](a, b T) bool {
	return a == b
}

type MyInt int

func main() {
	equal[int](10, 20) //正确
	equal[MyInt](10, 20) //错误
}

如果要使上面第二个调用正确,只需要修改Num中对int的定义即可

type Num interface {
	~int | float64
}