Fetch the repository succeeded.
2022年3月15日,go团队发布了Go 1.18,这个版本是个大型版本,其中包括新功能泛型的支持。 本篇学习记录Go 中泛型的基础知识
我们从一个math求和例子开始:
package main
import "fmt"
type Number interface {
int64 | float64
}
func main() {
// Initialize a map for the integer values
ints := map[string]int64{
"first": 34,
"second": 12,
}
// Initialize a map for the float values
floats := map[string]float64{
"first": 35.98,
"second": 26.99,
}
fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n",
SumIntsOrFloats(ints),
SumIntsOrFloats(floats))
}
// SumIntsOrFloats sums the values of map m. It supports both floats and integers
// as map values.
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
执行代码,输出:
Generic Sums, type parameters inferred: 46 and 62.97
func GenericFoo[P aConstraint, Q anotherConstraint](x,y P, z Q)
泛型函数调用分两个阶段
举个栗子:
package main
import (
"fmt"
"golang.org/x/exp/constraints"
)
func main() {
x, y := 2, 3
min := GMin[int](x, y)
fmt.Printf("Int-Generic GMin: %v and %v min = %v", x, y, min)
}
func GMin[T constraints.Ordered](x, y T) T {
if x < y {
return x
}
return y
}
运行代码,输出
Int-Generic GMin: 2 and 3 min = 2
GMin调用过程伪代码 :
fmin := GMin[float64]
m := fmin(2.71, 3.14)
接着我们来看一下 constraint
约束(constraint)规定了一个类型实参(type argument)必须满足的条件要求。如果某个类型满足了某个约束规定的所有条件要求,那么它就是这个约束修饰的类型形参的一个合法的类型实参
还是以上面的例子,跳转constraints pkg,可以看到 Ordered 是一个interface
type Ordered interface {
Integer | Float | ~string
}
其中
回到刚才的例子中,说明 x,y 只要是 Integer | Float | ~string 中的一种即符合要求。
假设我们使用了一个不正确(不能排序的类型)
x, y := true false
min := GMin[bool](x, y)
执行代码,输出错误
# tkingo.vip/egs/generics-demo
.\m.go:17:14: bool does not implement constraints.Ordered
// Package constraints defines a set of useful constraints
to be used// with type parameters.
package constraints
将把之前定义的约束移到它自己的接口中,以便您可以在多个地方重用它。以这种方式声明约束有助于简化代码,例如当约束更复杂时。 约束接口也可以引用特定类型。
type Number interface {
int64 | float64
}
还是上面的例子,我们改成自定义的 Number
package main
import (
"fmt"
)
func GMin[T Number](x, y T) T {
if x < y {
return x
}
return y
}
type Number interface {
int | int64 | float64
}
func main() {
x, y := 2, 3
min := GMin[int](x, y)
fmt.Printf("Int-Generic GMin: %v and %v min = %v", x, y, min)
}
执行代码,输出:
Int-Generic GMin: 2 and 3 min = 2
除了函数可以携带类型参数变身为“泛型函数”外,类型也可以拥有类型参数而化身为“泛型类型”,比如下面代码就定义了一个向量泛型类型
type Vector[T any] []T
这是一个带有类型参数的类型定义,类型参数位于类型名的后面,同样用方括号括起。在类型定义体中可以引用类型参数列表中的参数名(比如 T)。类型参数同样拥有自己的约束,如上面代码中的 any。在 Go 1.18 中,any 是 interface{}的别名,也是一个预定义标识符,使用 any 作为类型参数的约束,代表没有任何约束。
package main
import "fmt"
type Vector[T any] []T
func (v Vector[T]) Dump() {
fmt.Printf("%#v\n", v)
}
func main() {
var iv = Vector[int]{1, 2, 3, 4}
var sv Vector[string]
sv = []string{"a", "b", "c", "d"}
iv.Dump()
sv.Dump()
}
输出
main.Vector[int]{1, 2, 3, 4}
main.Vector[string]{"a", "b", "c", "d"}
Sign in to post a comment
Comment ( 0 )