升级Go版本到 1.18
下载地址:GO1.18
问题所在
相信有过其他语言编程基础的人,对于以下代码肯定看不下去:
以下代码来源与golang官网:https://go.dev/doc/tutorial/generics
package main
import "fmt"
func SumInts(m map[string]int64) int64 {
var s int64
for _, v := range m {
s += v
}
return s
}
func SumFloats(m map[string]float64) float64 {
var s float64
for _, v := range m {
s += v
}
return s
}
func main() {
ints := map[string]int64{
"first": 34,
"second": 56,
}
floats := map[string]float64{
"first": 35.98,
"second": 43.8,
}
sumInts := SumInts(ints)
sumFloats := SumFloats(floats)
fmt.Println("结果:", sumInts, sumFloats)
}
蛋疼的临时解决方案
在Go1.18之前也不是没有办法解决,可以使用接口类型实现:
func SumIntOrFloats(m map[string]interface{}) (int64, float64) {
var s1 int64
var s2 float64
for _, v := range m {
switch v.(type) {
case int64:
vint := v.(int64)
s1 += vint
case float64:
vfloat := v.(float64)
s2 += vfloat
}
}
return s1, s2
}
以上代码写的也很别扭,还不如多写一个方法,反而更简单一些,你如果有其他更简单的实现方式也可以留言。
泛型终于来了--被放鸽子多次之后
直接上代码:
package main
import "fmt"
//类型参数约束
type comparable interface {
~string | ~int64 | ~float64
}
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
func main() {
ints := map[string]int64{
"first": 34,
"second": 56,
}
floats := map[string]float64{
"first": 35.98,
"second": 43.8,
}
orFloats := SumIntsOrFloats(ints)
intsOrFloats := SumIntsOrFloats(floats)
fmt.Println("结果:", orFloats, intsOrFloats)
}
类型参数
看了以上泛型代码,没错这就是Go的泛型语法
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V
func 方法名[类型参数](形式参数)返回值
简单案例
//这里类型参数限制,Max方法可以接收int64以及float64类型的参数
func Max[T int64 | float64](a, b T) T {
if a >= b {
return a
}
return b
}
func main(){
var a int64 = 1
var b int64 = 2
//这里调用的时候参数类型必须一致,a,b类型要么int64要么都是float64
res := Max(a, b)
fmt.Println(res)
var c float64 = 1.1
var d float64 = 2.1
res1 := Max(c, d)
fmt.Println(res1)
}
类型参数约束
类型参数约束条件简单表示形式
1,直接写在 [] 中
Max[T int64 | float64]
2,定义约束接口 Number
type Number interface {
int64 | float64
}
func Max[T Number](a, b T) T {
if a >= b {
return a
}
return b
}
3,标准库内置的类型参数约束
any
// any is an alias for interface{} and is equivalent to interface{} in all ways.
// any其实就是一个空接口,所有类型,也就是没有约束
type any = interface{}
func useAny[T any](t T) T {
return t
}
comparable
// comparable is an interface that is implemented by all comparable types
// (booleans, numbers, strings, pointers, channels, arrays of comparable types,
// structs whose fields are all comparable types).
// The comparable interface may only be used as a type parameter constraint,
// not as the type of a variable.
// 可比较类型,只能用于泛型约束条件中,不能当作变量类型使用
type comparable interface{ comparable }
func useComparable[T comparable](t T) T {
return t
}
关于内置的comparable不清楚为啥在map key的约束中不能使用,以下使用了自己定义的comparable约束,但是使用Go内置的comparable直接飘红了
//参数约束
type comparable interface {
~string | ~int64 | ~float64
}
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V
constraints
非标准库的泛型约束,在Go1.18的beta版本中Go开发者其实有把constraints放到标准库中,后面考虑到最佳实践问题,具体需不需要constraints包中的约束就交给用户去实践,因此放在了exp包下 golang.org/x/exp/constraints
package constraints
type Signed interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
}
type Unsigned interface {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}
type Integer interface {
Signed | Unsigned
}
type Float interface {
~float32 | ~float64
}
type Complex interface {
~complex64 | ~complex128
}
type Ordered interface {
Integer | Float | ~string
}
关于泛型约束还有很多其他的写法,这里就不做展开,先介绍简单的使用方式,后续在慢慢深入讲解。
总结
1,本文讲解了没有泛型时写通用代码遇到的问题
2,简单泛型的使用方式
3,泛型类型参数
4,类型参数约束
5,内置的参数约束
6,非标准库的泛型参数约束
参考链接:
1,https://go.dev/doc/tutorial/generics
文章评论