download:Go实战训练营全新升级第5期无密
简介
什么是泛型?
泛型编程是一种计算机编程风格,编程范式,其中算法是根据后来指定的类型编写的,然后在需要时为作为参数提供的特定类型进行实例化。常用的编程语言也基本支持泛型的这个特性,比如C++、C#、Java、Python、Rust、Swift、TypeScript、kotlin等。泛型具有以下特征:
参数化类型:类型作为函数参数传递。
- 更强的类型检查:泛型使编译器能够在编译期间检查类型,以提高类型安全性并减少运行时由不匹配的对象类型导致的异常。
- 代码保存和抽象表示
文章图片
很长一段时间,围棋没有通用函数。参考《为什么Go语言没有泛型——面向信仰的编程》一文。这篇文章讨论了Golang不支持泛型的两个原因:
【极客时间-Go实战训练营全新升级第5期无密】通用困境使得开发者不得不在开发效率、编译速度和运行速度之间做出选择。
目前社区里的Go语言方案都是有缺陷的,但是Go团队认为泛型的支持还不够迫切。
这篇文章认为还有另一个原因:
泛型会让Golang变得更加复杂和深远。在Go 1.18中,只提供了泛型特性,很多系统库实现都没有转换成泛型样式,泛型都是和Golang.org/x/exp库相关的。
然而,在2020年度Go开发者调查中,26%的受访者表示Go缺乏他们需要的语言功能,88%的受访者选择泛型作为关键的缺失功能。
与其他语言中的泛型相比
Go没有太多负担,但更注重设计,而J
ava、C++
等老牌语言由于兼容性或其他原因迭代较慢。这里比较一下Go的泛型和已建立的语言泛型在语法、类型约束、实现原理等方面的区别。:语法去// Go泛型泛型语法是括号。
func Print[T any](t T) {
fmt。Printf("打印类型:%T\n ",T)
}
复制代码爪哇公共静态无效打印(T t) {
System.out.println("打印类型:"+ t.getClass()。getName());
}
Go// 方法限制
type Stringer interface {
String() string
}
// 类型集合
type Types interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 |
~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64
}// 限定为 Types
funcSub[T Types](t1, t2 T) T {
return t1 - t2
}
复制代码Javapublic class Main{
// 泛型限定 必须是Collection 类型的子类才可以被接收
public static void print(T t){
System.out.println(t);
}public static void main(String[] args){
print(Arrays.asList(1,2,3));
}
}
实现原则
小贴士:
单一化指的是为了我们要处理的不同类型的数据而多次复制代码。单一化通常比基于继承的多态代码更快,但代价是编译时间和二进制大小。事实上,单态确保了零开销调用,而基于继承的多态需要通过虚拟调度表的间接指针。此外,编译器可以专门优化和/或内联单例代码。
去
提到泛型实现,Go泛型实现的一个关键特点就是只部分使用了singleton。在Go中,singleton只是部分应用了一种叫做
“GC shape stenciling with dictionaries”
的技术。这样做的主要效果是,指针类型或接口的所有参数都被视为属于同一个基础类型,这意味着只生成该函数的单态版本。将此与接受算术参数的函数进行比较,如int 32和float64,它们都有自己专用的函数版本。爪哇
大多数关于Java泛型的抱怨都集中在类型擦除上。这种设计没有类型擦除。泛型类型的反射信息将包括完整的编译时类型信息。
在Java类型通配符(列表
C++
C++模板不会对类型参数施加任何约束(除非采用概念上的建议)。这意味着更改模板代码可能会意外破坏远程实例化。这也意味着只有在实例化时才会报告错误消息,并且可能嵌套很深,难以理解。这种设计通过强制和显式约束避免了这些问题。
C++支持模板元编程,可以看作是在编译时完成的普通编程,语法与非模板C++完全不同。这种设计没有类似的特点。这节省了相当大的复杂性,同时损失了一些功率和运行时效率。
++使用两阶段名称查找,其中一些名称在模板定义的上下文中找到,一些名称在模板实例化的上下文中找到。在这个设计中,所有的名字都是在书写的地方查找的。
实际上,所有C++编译器在实例化每个模板时都会编译它。这将降低编译时间。这种设计在如何处理泛型函数的编译方面提供了灵活性。
推荐阅读
- go里边一个让新手误解,让老炮犯错的小知识点
- 为什么 signal.Notify 使用缓冲通道()
- Go中的网络轮询器(1)--Epoll在Go中的抽象
- net包的使用
- atomic
- 条件变量 Cond
- 类型别名与类型定义的区别
- Go|猿创征文|我的Go成长之路道阻且长
- go-常用类库