泛型在 Go 1.18 版本加入,您需要开始使用 1.18 版本,您可以在此处下载。
什么是泛型?为什么 Go 需要它?
abab
intint64float
intfloat
floatint
因此,唯一合适的解决方案是编写两个有重复功能的函数,如下所示。
Add(a,b int) intAddFloat(a,b float32) float32
interface{}interface
这就是泛型解决的问题,也是为什么这么多开发人员非常渴望看到它发布的原因。
泛型在 Go 1.18 发布后,上述问题的解决方案变得很简单。您可以点击此处获取可运行的代码。
泛型的工作原理
让我们深入了解泛型的基本用法。
Add
func FunctionName
(a int)a
func Add(a, b int) int {
return a + b
}
复制代码
Addabint
解释函数参数看起来是愚蠢的,但是了解泛型之前,先了解他它是至关重要的。
[][](a,b int)
类型参数的参数名通常大写,使它们更容易被发现。
V[V int]
func Add[V int](a, b int) int {
return a + b
}
复制代码
VVV
abVV
func Add[V int](a, b V) V {
return a + b
}
复制代码
intint
floatAddfloat32 does not implement intAddint|orV
func Add[V int | float32](a, b V) V {
return a + b
}
复制代码
AddAdd
在您成为泛型高手之前的最后一件事。您可以在调用的泛型函数前设置要返回的参数类型。如下所示。
result := Add[int](a, b)
复制代码
~
我们现在可以使用泛型函数了,但是还剩下一些细节。想象一下,如果您想控制在泛型函数中返回的数据类型应该怎么办?
Add[int](1,2) // 希望返回 int 数据类型
Add[int64](1,2) // 希望返回 int64 数据类型
复制代码
我们现在可以告诉函数返回什么数据类型,太棒了!
Addalias
您将无法告诉函数返回什么类型的数据。
// 创建一个自定义类型 OwnInteger
type OwnInteger int
var myInt OwnInteger
myInt = 10
Add(myInt, 20) // 这将引发 painc,因为 myInt 不属于任何类型
复制代码
~
通过泛型完成类型约束
generic functionsgeneric types
ResultsAddable
type Results[T Addable] []T
复制代码
SliceAddableResultsAddable
Addable
var resultStorage Results[Addable]
复制代码
Addableinterface contains type constraints
anyResultsanyinterface{}
通过泛型完成接口约束
目前为止,我们只为单个类型进行约束,但是泛型也可以用作接口的约束。
Move
type Moveable interface {
Move(int)
}
// Move 是一个泛型函数,它接收 Moveable 并对其进行移动
func Move[V Moveable](v V, meters int) {
v.Move(meters)
}
复制代码
PersonCar
到目前为止,我们只使用了一个通用参数来保持简单。但请记住,您可以添加多个,并输出多个。
MoveableSubtractableMoveDistance
func Move[V Moveable, S Subtractable](v V, distance S, meters S) S
复制代码
panicMoveintSubtractable
Subtractable
不过,有一种方法可以得到我们想要的,那就是泛型结构体。
Moveable
// 实现这个接口,需要一个具有 Subtractable 约束的泛型类型
type Moveable[S Subtractable] interface {
Move(S)
}
复制代码
[]
type Car[S Subtractable] struct {
Name string
}
type Person[S Subtractable] struct {
Name string
}
func main(){
p := Person[float64]{Name: "Guowei"}
c := Car[int]{Name: "POLO"}
}
复制代码
我们结构体实现接口的方法也需要修改。
func (p Person[S]) Move(meters S) {
fmt.Printf("%s moved %d meters\n", p.Name, meters)
}
func (c Car[S]) Move(meters S) {
fmt.Printf("%s moved %d meters\n", c.Name, meters)
}
复制代码
MoveMoveable
func Move[V Moveable[S], S Subtractable](v V, distance S, meters S) S {
v.Move(meters)
return Subtract(distance, meters)
}
复制代码
mainCarintPersonfloat64Movefloat64Moveint
func main(){
p := Person[float64]{Name: "GuoWei"}
c := Car[int]{Name: "POLO"}
milesToDestination := 100
distanceLeft := Move(c, milesToDestination, 95)
fmt.Println(distanceLeft)
fmt.Println("DistanceType: ", reflect.TypeOf(distanceLeft))
newDistanceLeft := Move[Person[float64], float64](p, float64(distanceLeft), 5)
fmt.Println(newDistanceLeft)
fmt.Println("DistanceType: ", reflect.TypeOf(newDistanceLeft))
}
复制代码
您可以点击此处获取可运行的代码。
MoveMove[Person[float64], float64]
func Move[S Subtractable, V Moveable[S]](v V, distance S, meters S) S {
v.Move(meters)
return Subtract(distance, meters)
}
newDistanceLeft := Move[float64](p, float64(distanceLeft), 5)
复制代码
总结
Go
Go1.18
其他
封面来自互联网。