Go 终于在1.18版本中引入了泛型实现方式。分析下泛型的实现过程。
首先, 我看到的是一段泛型示例:
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("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\n",
SumNumbers(ints),
SumNumbers(floats))
}
// 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 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
}
// SumNumbers sums the values of map m. Its 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
}
这段代码取自:Tutorial: Getting started with generics - The Go Programming Language
上面的代码看了后,有如下疑问:
泛型有两个场景:
-
定义函数的时候
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {}
问:上面的函数签名中 K comparable 是否是必须的?
问: comparable 是否是定义泛型包含对象 int64 float64 都必须具有的属性限制?
问: 函数签名返回值类型中 map[K]V的 K 是否是使用泛型后,返回值签名里必须有的?
-
定义接口的时候(
Number是接口)func SumNumbers[K comparable, V Number](m map[K]V) V {}
问:使用接口定义泛型的时候, K comparable 是否是必须的?
问:使用接口定义泛型的时候,函数签名返回值类型中 map[K]V的 K 是否是必须的?
针对上面的问题,我本来首先想到的是查资料, 但是由于Go1.18刚发布, 网上的资料几乎都是官方文档那一篇文章(或者它的翻译)。所以只能本地安装Go1.18, 然后在本地来验证。
为了分析上面的问题, 我重写了上面的代码,结果如下:
package main
import "fmt"
type Number interface {
int64 | float64
}
func main() {
// Initialize a map for the integer values
ints := []int64{
34,
12,
}
// Initialize a map for the float values
floats := []float64{
35.98,
26.99,
}
fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n",
SumIntsOrFloats(ints),
SumIntsOrFloats(floats))
fmt.Printf("Generic Sums with Constraint: %v and %v\n",
SumNumbers(ints),
SumNumbers(floats))
}
// SumIntsOrFloats sums the values of map m. It supports both floats and integers
// as map values.
func SumIntsOrFloats[V int64 | float64](m []V) V {
var s V
for _, v := range m {
s += v
}
return s
}
// SumNumbers sums the values of map m. Its supports both integers
// and floats as map values.
func SumNumbers[V Number](m []V) V {
var s V
for _, v := range m {
s += v
}
return s
}
执行结果如下:
从上面的结果, 上面的问题可以得到如下结论:
问:上面的函数签名中 **K comparable** 是否是必须的?
- 答:不是必须的
问: **comparable** 是否是定义泛型包含对象 **int64** **float64** 都必须具有的属性限制?
- 答:虽然在签名里面
**comparable**不是必须的, 但是**comparable**是是定义泛型包含对象**int64****float64**都必须具有的属性, 不然不能对**int64****float64**做累加操作
问: 函数签名返回值类型中 **map**``**[K]V**的 **K** 是否是使用泛型后,返回值签名里必须有的?
- 答:不是必须的
问:使用接口定义泛型的时候, **K comparable** 是否是必须的?
- 答:不是必须的
问:使用接口定义泛型的时候,函数签名返回值类型中 **map**``**[K]V**的 **K** 是否是必须的?
-
答:不是必须的
后续再对 模糊测试 workspace 工作区 进行挨个分析。