Go泛型系列:Go1.18 类型约束那些事

发布于 2021-11-18 17:35 ,所属分类:软件编程学习资料

阅读本文大概需要 6 分钟。

大家好,我是 polarisxu。

上篇《Go泛型系列:提前掌握Go泛型的基本使用》简单讲解了泛型中的约束,但约束相关内容远不止那些,本文介绍更多约束相关内容。

请安装最新的 tip 版本,方便验证本文的内容。当然,也可以通过 https://gotipplay.golang.org/在线验证。

01 语法变更

上次提到,定义约束的语法类似这样:

typeAddableinterface{
typeint,int8,int16,int32,int64,uint,uint8,uint16,uint32,uint64,uintptr,float32,float64,complex64,complex128,string
}

不过目前已经确认,语法改成如下形式:

typeAddableinterface{
int|int8|int16|int32|int64|uint|uint8|uint16|uint32|uint64|uintptr|float32|float64|complex64|complex128|string
}

对于这样的修改,大家褒贬不一。就语义来说,新的方式|有或之意,更贴切,而且少了一个type,更简洁。

02 额外用法

除了以上提到的优点,新的方式还还有额外的用途,也就是不用每次都定义一个接口约束。

看一个具体示例:

packagemain

import(
"fmt"
)

funcadd[Tint|float64](a,bT)T{
returna+b
}

funcmain(){
fmt.Println(add(1,2))
fmt.Println(add(1.2,2.3))
//fmt.Println(add("a","b"))
}
//Output:
//3
//3.5

最后注释的一行代码,会编译报错:string does not satisfy int|float64

注意 add 函数的泛型约束:T int|float64。如果约束是逗号分隔,无法采用这种语法:

funcadd[Tint,float64](a,bT)T

以上代码显然很不友好,编译器也不好解析。

采用了|后,不需要每次都定义接口约束,可以让代码更少。不过,这种方式建议只在少数类型约束时才适合,否则可读性太差。

除了以上用法,约束还有一种用法。

在 Go 语言中,基于某类型定义新类型,有时可能希望泛型约束是某类型的所有衍生类型。看一个具体例子:

packagemain

import(
"fmt"
)

funcadd[T~string](x,yT)T{
returnx+y
}

typeMyStringstring

funcmain(){
varxstring="ab"
varyMyString="cd"
fmt.Println(add(x,x))
fmt.Println(add(y,y))
}

//Output:
//abab
//cdcd

注意 add 函数的签名:

funcadd[T~string](x,yT)T

约束~string表示支持 string 类型以及底层是 string 类型的类型,因此 MyString 类型值也可以传递给 add。

03 注意事项

约束形式的多样性,导致 Go 泛型语法一下子复杂起来:

//没有任何约束
funcadd[Tany](x,yT)T
//约束Addble(需要单独定义)
funcadd[TAddble](x,yT)T
//约束允许int或float64类型
funcadd[Tint|float64](x,yT)T
//约束允许底层类型是string的类型(包括string类型)
funcadd[T~string](x,yT)T

在泛型中,有些场景可能想当然可以成立,但结果可能不成立,在使用时需要注意(当然,不排除将来支持)。比如:

funcMakeChan[Tchanbool|chanint](cT){
_=make(T)//错误
_=new(T)//正确
_=len(c)//正确
}

//以下代码无法编译:
//cannotrangeoverc(variableoftypeTconstrainedby[]string|map[int]string)(Thasnostructuraltype)
funcForEach[T[]string|map[int]string](cT,ffunc(int,string)){
fori,v:=rangec{
f(i,v)
}
}

ForEach 函数的签名,你能看懂吗?泛型确实让 Go 复杂起来了,虽然语法允许,但建议大家以后写泛型代码时一定要尽量保证可读性。




往期推荐
  • Go泛型系列:提前掌握Go泛型的基本使用


我是 polarisxu,北大硕士毕业,曾在 360 等知名互联网公司工作,10多年技术研发与架构经验!2012 年接触 Go 语言并创建了 Go 语言中文网!著有《Go语言编程之旅》、开源图书《Go语言标准库》等。


坚持输出技术(包括 Go、Rust 等技术)、职场心得和创业感悟!欢迎「polarisxu」一起成长!也欢迎加我好友交流:gopherstudio

相关资源