泛型
1.泛型是什么?为什么要用泛型?
在开发中,会有一些复用性很强的功能,它被应用到很多地方,但为了适用会被不断重写,这很低效。例如一个intADD函数,他能进行 int 的加法,假如我们想进行 float 加法,又得重写一个floatADD函数,泛型就是为了解决这个问题而推出的功能。
想要接收多种类型的参数,可以使用空接口来接收,在函数里面进行类型断言后实现操作。这是泛型出现前的做法,虽然没那么低效,但也称不上高效,使用泛型更加高效。
2.泛型函数语法
go
func func_name[T 类型1 | 类型2 | ... ,类型参数...](形参 T, ...) 返回值 {
//...
}
相比普通函数,泛型多了一个类型参数,和其他语言不同,Go用中括号[ ] 来装载类型参数,而不是尖括号< >。
go
//举个例子
func add[T int | float64 | float32, Q string | int | float32 | float64](a, b T, c Q) T {
fmt.Println(c)
return a + b
}
func main() {
add(3, 3.14, "Go")
}
3.类型参数
上述例子中, T 和 Q 都是类型参数,可以有多个类型参数;而跟在类型参数后面的是类型约束,也就是限定类型的范围。
我们知道内置类型是不能自定义方法的,所以有的时候我们会基于一个内置类型来自定义类型,例如 type myint int,每有一个这种自定义类型,泛型的类型参数又多一个,这很繁琐,而且不好看。
因此 Go 使用 ~ 来表示底层类型一致,例如 ~int 可以代表 int 和 myint,以及所有 只基于int的自定义类型。
4.类型集
可以预见的是,如果类型参数的类型约束很多,那么代码的可读性会很差。因此 Go 将接口扩展,能够通过接口定义类型集 来进行类型约束。
go
type number interface {
~int | ~float64 | ~float32
}
type pmsg interface {
~string | ~int | ~float32 | ~float64
}
func add[T number, Q pmsg](a, b T, c Q) T {
fmt.Println(c)
return a + b
}
func main() {
add(3, 3.14, "Go")
}
5.泛型类型
语法如下:
go
type TypeName[T Type] struct {
// ...
}
举个例子:
go
package main
import "fmt"
type Stack[T any] struct {
data []T
}
func (s *Stack[T]) Push(x T) {
s.data = append(s.data, x)
}
func (s *Stack[T]) Pop() T {
n := len(s.data)
x := s.data[n-1]
s.data = s.data[:n-1]
return x
}
func main(){
s := Stack[int]{}
for i:=1;i<=5;i++{
s.push(i)
}
fmt.Println(s.Pop())
fmt.Println(s.Pop())
}
6.泛型接口
go
package main
import (
"fmt"
)
type Person[T any] interface {
Say(T) T
}
type Student[T any] struct {
Name string
}
func (s *Student[T]) Say(t T) T {
fmt.Println(s.Name, "say:", t)
return t
}
type Teacher[T any] struct {
Name string
}
func (s *Teacher[T]) Say(t T) T {
fmt.Println(s.Name, "say:", t)
return t
}
func main() {
var p1 Person[string] = &Student[string]{Name: "Tom"}
fmt.Println("main:", p1.Say("ccc"))
var p2 Person[int] = &Teacher[int]{Name: "Ann"}
fmt.Println("main:", p2.Say(123))
}
小结
- 泛型的使用范围并没有想象中那么大,一般来说,实现通用的数据结构 或 不同类型需要实现公用方法 时才会用到。
- 虽然很相似,但是不要将 interface 类型全用泛型替换,这样性能并不会更好。
- 不要滥用泛型。