使用非泛型函数
golang在没有泛型的时候,如果我们要计算一个map的所有value之和,比如该map的key为string类型,value是int64类型,我们需要定义以下函数:
// SumInts adds together the values of m.
func SumInts(m map[string]int64) int64 {
var s int64
for _, v := range m {
s += v
}
return s
}
同时我们又有另外一个map也需要计算所有value之和,该map的key也为string类型,但是value是float64类型,所以我们还需要定义另外一个函数:
// SumFloats adds together the values of m.
func SumFloats(m map[string]float64) float64 {
var s float64
for _, v := range m {
s += v
}
return s
}
然后在分别调用两个函数执行计算操作
1. 先定义两个map
// 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,
}
2. 调用函数
fmt.Printf("Non-Generic Sums: %v and %v\n",
SumInts(ints),
SumFloats(floats))
可以发现SumInts和SumFloats除了接收参数不同之外内部逻辑完全相同,如果有更多参数类型不不同但功能逻辑完全的功能,会发现到处都是重复的代码,所以就有了泛型来解决这个问题
使用泛型函数
定义泛型函数
实现同样的计算一个map的value之和,可以定义如下函数:
// SumIntsOrFloats sums the values of map m. It supports both int64 and float64
// as types for 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
}
- 该函数声明了两个类型参数,即[]中的K和V,和一个要使用这两个类型参数的map类型的参数m,返回一个V类型的值
- 其中comparable是一个在go里面预定义的类型,表示K这个参数需要支持== 和 != 操作
- 所以可理解为该函数接收一个map参数,该map的key是一个comparable类型的值,value是int64或者float类型的值,所以定义一个map[int]int64也是可以用这个函数计算的,因为int类型也是一个comparable类型的参数,可以做==和!=操作
调用函数
fmt.Printf("Generic Sums: %v and %v\n",
SumIntsOrFloats[string, int64](ints),
SumIntsOrFloats[string, float64](floats))
一个函数就解决了问题,如果还要添加int类型,float类型或者其他类型,也只不过是在[]中再添加对应的类型即可,并不需要另外重写一个函数
类型推导
go编译器在调用泛型函数时会自动推导出参数类型,所以调用泛型函数时可以省略传入参数类型
调用函数
fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n",
SumIntsOrFloats(ints),
SumIntsOrFloats(floats))
声明类型约束
在[]中定义了一个V的类型参数,当只有几个类型时看着还比较清晰,如果类型很多,比如float,float64,int,int64,int32等等等等,看着不是那么清晰了,所以可以声明一个类型约束,定义一个Number类型的interface,类型为int64或float64,如果有其他类型可以一直在后面加
1. 定义类型约束
type Number interface {
int64 | float64
}
2. 使用类型约束
// SumNumbers sums the values of map m. It supports both integers
// and floats as map values.
func SumNumbers[K comparable, V Number](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
3. 调用函数
fmt.Printf("Generic Sums with Constraint: %v and %v\n",
SumNumbers(ints),
SumNumbers(floats))
总结
泛型是为了解决出现太多重复代码问题,最佳实践如下:
1. 给包含很多类型的变量声明类型约束,直接在泛型函数中使用该类型约束
2. 调用泛型函数时不必添加类型
附全文代码:
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,
}
intsInts := map[int]int64{
0: 10,
1: 20,
}
fmt.Printf("Non-Generic Sums: %v and %v\n",
SumInts(ints),
SumFloats(floats))
fmt.Printf("Generic Sums: %v and %v\n",
SumIntsOrFloats[string, int64](ints),
SumIntsOrFloats[string, float64](floats))
fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n",
SumIntsOrFloats(ints),
SumIntsOrFloats(floats))
fmt.Printf("Generic Sums with Constraint: %v and %v and %v\n",
SumNumbers(ints),
SumNumbers(floats),
SumNumbers(intsInts))
}
// SumInts adds together the values of m.
func SumInts(m map[string]int64) int64 {
var s int64
for _, v := range m {
s += v
}
return s
}
// SumFloats adds together the values of m.
func SumFloats(m map[string]float64) float64 {
var s float64
for _, v := range m {
s += v
}
return s
}
// SumIntsOrFloats sums the values of map m. It supports both int64 and float64
// as types for 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
}
// SumNumbers sums the values of map m. It supports both integers
// and floats as map values.
func SumNumbers[K comparable, V Number](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
执行结果如下:
$ go run generic.go
Non-Generic Sums: 46 and 62.97
Generic Sums: 46 and 62.97
Generic Sums, type parameters inferred: 46 and 62.97
Generic Sums with Constraint: 46 and 62.97 and 30
参考
Tutorial: Getting started with generics - The Go Programming Language