近日,Go 团队官宣 Go 1.18 正式发布!新版本有何值得关注的特性?快跟随汇量科技 Mobvista 技术 VP 兼首席工程架构师蔡超,一起感受全新升级的 Go——
文/汇量科技技术 VP 兼首席工程架构师 蔡超
基本语法
定义可接受类型列表(constraint)
简单来说,Go 的泛型就是将参数类型定义为一个可接受类型的列表(称为constraint)。
直接上例子
例1: 方法定义上使用泛型
例2: 结构类型定义上使用泛型
以上例子中使用了一个预置的 constraint “any”,这里 any 就相当于 interface{},表示任何类型。
让列表更简单
用 “~”简化衍生类型的声明
上面泛型函数只能接受 constraint 列表中的类型作为调用的参数,包括这些类型的别名。但对于列表中类型的衍生类型就不能接受了。
例如:
编译以上程序会引发编译错误,在 Go 中为了简化扩展类型的定义,我们可以通过"~"来表示支持类型扩展类型。利用这种方式修改方法定义即可修复上面的编译问题。
定义 constraint 类型
虽然有了上面的对于扩展类型的简化定义方式,但还是会很容易产生很长的 contraint 类型列表,而且这个列表往往会需要在很多方法定义中重复。
为了简化和复用复杂的类型列表(constraint)声明,在 Go1.18 中可以通过 interface 来定义一个 constraint 类型。
1. interface 中定义 constraint 类型支持的方法
这种方式下方法所接受的类型必须要实现了该接口定义,即实现了该接口中包含的方法。
这里你可能会有一个问题:既然使用了 interface,那完全可以使用多态--以接口 Addable 作为方法的参数,定义如下:
问题来了:这里的 AddPoly 和上面使用泛型定义的 AddGen 一样吗?
答案是不一样的。
AddGen 的传入参数(a,b) 必须是同一类型,而不仅仅是都实现了 Addable 接口,上列中要么都是 type1,要么都是 type2。
而 AddPoly 方法就不同了,传入参数只要是实现了 Addable 就可以,即(a,b) 可以一个是 type1,另一个是 type2。
2. interface 中直接包含可接受类型列表
这里就比较直接,可以在一个 interface 中定义可接受类型的列表
这个 constraint interface 可以在不同的地方被复用,Google 在"golang.org/x/exp/constraints"包中也贴心地提供了很多常用的 constraint interface。
关于性能
Go 的泛型实现影响性能吗?这是很多程序员最关心的问题。我们直接通过 Benchmark 程序来看结果。
1. constraint 为基础计算类型
可以看到, Go 泛型对于基本类型的影响几乎没有。
2. constraint 为接口定义的类型(这里指类型需要实现接口中的方法)
这种情况下泛型的性能明显要差于原有的多态实现。所以,类似情况最好不要使用泛型来替代多态,不仅没有简化程序,反而对性能有一定影响。
写给 Java 程序员:
关于类型擦除
Java 程序员都知道,Java 的泛型实现是编译时期的,在运行时是被擦除的,例如:
由于类型擦除的缘故,li.getClass() == lf.getClass() 的结果是 true。
而 Go 的泛型则不是通过这种方式实现的,Go 采用了一种不完全的单态化(monomorphization) 被称为“GCShape stenciling with Dictionaries” 。这种实现方式也导致了我们在前面看到的性能测试的结果,具体细节,我将在未来的文章中和大家讨论。
由于没有类型擦除,reflect.TypeOf(li) == reflect.TypeOf(lf)结果返回为 false。
以上为该特性的简单介绍。如需了解更多细节,可参考官方文档进行学习。
关注蔡超谈软件,了解更多内容?
————————————
不想再错过你的云端干货?点击“阅读原文”,或关注“云上说禅”吧!
相关阅读
- 最实用的云计算知识科普及实践教学
- 最具洞见的行业趋势解读
- 最新鲜的产品动态
- 最有趣的技术人日常
文章评论