## 1 go范型约束引起的思考
go已有的接口实现自然是无法替代范型了,否则社区也不会一直有范型的需要。
但看了go范型的实现,却引起了我对go接口为什么不能替代范型进行了的思考。首先看下go范型约束的定义:
```go
// 直接使用接口约束
type Stringer interface {
String() string
}
// 使用新增的约束语法
type Addable interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | uintptr | float32 | float64 | complex64 | complex128 | string
}
```
go范型的约束是使用的接口进行的约束,其中新的约束语法虽然表面上看是约束的类型,但从addable意思来看,实际上还是约束的接口,即对类型的行为进行了约束,如这些类型都是有“+”的接口。所以从这方面来看,go接口应该是有潜力替代范型的,那到底go接口缺了哪些问题,导致go依旧需要范型呢?
## 2 从范型的定义来看
首先先从范型是什么来看下这个问题,某度搜下,“泛型程序设计(generic programming)是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。”,感觉不知道说了什么,算了直接看代码:
```go
func add[T Addable](a, b T) T {
return a + b
}
```
从这个简单的例子看下接口和范型的差别:
- 约束参数的类型,必须具备某些接口的行为能力。这个接口也可以满足,范型也是使用接口做的约束。
- 返回值类型的指定。这个接口是无法做到的,返回值只能是静态指定类型,或者返回接口。
- 使用内置类型的默认接口,如:+、-、<、[]、<-等等。这个接口是无法满足,接口不支持定义内置类型的默认接口。
可以看出,范型确实有接口不能满足的特性,导致go语言引入了新特性--范型,增加了go的复杂性,是略微有些遗憾的。
## 3 接口的遗憾及弥补方式讨论
go接口是非常好用的特性,特别是支持鸭子类型让go的编程方便了很多,不用去考虑继承等关系就能使用相同的逻辑处理不同类型,让go的接口差一点就干掉范型,但最终还是没能实现,还是比较遗憾。go接口虽然是默认特性,但却不能算是go的一等公民,因为go内置类的默认方法并不是接口,导致了接口无法对内置类型进行约束,否则就不需要范型的约束包constraints了。
那这个遗憾是否能够弥补呢?这里做下设想,给go的接口增加以下两个特性:
### 3.1 增加接口到类型的动态转换
因为支持鸭子类型的愿意,go的类型转接口是很方便,是动态转换,类型可以直接转换为接口,不需要做强制转换。但接口转类型则没那么方便,必须是静态转换,如any.(int)代码中明确了int类型后才能将any接口转换为int类型,因此需要补充这个缺憾,使得接口到类型也可以动态转换。
如定义:any.(this)可以将接口any动态的转换为any接口的原始转换类型。举例如下:
```go
// go范型的函数定义
func add[T Addable](a, b T) T {
return a + b
}
// 支持接口与类型动态转换的方式,使用.(this)动态的将接口转换为原始类型,跟范型类似的能力
func add(a, b Addable) Addable.(this) {
return a + b
}
```
这个特性很简单就解决了附录中自引用接口[3]的问题。
### 3.2 内置类型实现默认接口
这里是将接口作为go的一等公民,所有内置类型(如int、string、float等)的的默认操作,都可以作为接口使用。如+、<、<-、[]等等。实现方式之一,默认操作都有对应的函数,如int的+操作,默认等同于Add函数。这样
就不需要针对内置函数增加constraints包了,直接使用以下接口:
```go
// .(this)代表与调用者相同的类型
type Addable interface {
Add(b Addable.(this)) Addable.(this)
}
```
这个接口不论是内置类型,还是自定义的类型,都可以使用这个接口,实现范型的能力。
## 4 最后
这只是个突然冒出来的想法,应该有不少问题,请大家指点。
## 附录:
- [Go 泛型简明入门教程](https://mp.weixin.qq.com/s/_pJXLJ6W9BFZyWBud7agPQ)
- [Go泛型系列:Go1.18 类型约束那些事](https://mp.weixin.qq.com/s/FFxNpRVgs-v9cIKWCLeN4Q)
- [Go 1.18 中的自引用接口,代码看得懂吗?](https://mp.weixin.qq.com/s/6b6plq2Dzm-488j8BQePoQ)