我们看到,泛型类型中的类型参数可以用来作为类型声明中字段的类型(比如上面的 element 类型)、复合类型的元素类型(比如上面的 Set 和 Map 类型)或方法的参数和返回值类型(如 NumericAbs 接口类型)等。
如果要在泛型类型声明的内部引用该类型名,必须要带上类型参数,如上面的 element 结构体中的 next 字段的类型:*element[T]。按照泛型设计方案,如果泛型类型有不止一个类型参数,那么在其声明内部引用该类型名时,不仅要带上所有类型参数,类型参数的顺序也要与声明中类型参数列表中的顺序一致,比如:
type P[T1, T2 any] struct {
F *P[T1, T2] // ok
}
复制代码
不过从实测结果来看,对于下面不符合技术方案的泛型类型声明也并未报错:
type P[T1, T2 any] struct {
F *P[T2, T1] // 不符合技术方案,但Go 编译器并未报错
}
复制代码
5.2 使用泛型类型
和泛型函数一样,使用泛型类型时也会有一个实例化(instantiation)过程,比如:
var sl = maxableSlice[int]{
elems: []int{1, 2, -4, -6, 7, 0},
}
复制代码
Go 会根据传入的类型实参(int)生成一个新的类型并创建该类型的变量实例,sl 的类型等价于下面代码:
type maxableIntSlice struct {
elems []int
}
复制代码
看到这里你可能会问:泛型类型是否可以像泛型函数那样实现类型实参的自动推断呢?很遗憾,目前的 Go 1.21.4 尚不支持,下面代码会遭到 Go 编译器的报错:
var sl = maxableSlice {
elems: []int{1, 2, -4, -6, 7, 0}, // 编译器错误:cannot use generic type maxableSlice[T ordered] without instantiation
}
复制代码
不过这一特性在 Go 的未来版本中可能会得到支持。
既然涉及到了类型,你肯定会想到诸如类型别名、类型嵌入等 Go 语言机制,那么这些语言机制对泛型类型的支持情况又是如何呢?我们逐一来看一下。
5.2.1 泛型类型与类型别名