自 Go 1.18 支持泛型后, Go interface 的意义已经彻彻底底的改变了,除了先前代表的方法集的意义外,还被用作泛型的类型约束(type constraint)的功能, interface已经不再是以前那个单纯的少年了。
在Go 1.17.x以及以前的版本中,interface是这样定义的:
An interface type specifies a method set called its interface. A variable of interface type can store a value of any type with a method set that is any superset of the interface. Such a type is said to implement the interface. The value of an uninitialized variable of interface type is nil.
接口类型定义了一个方法集合,称之为接口(interface)。接口类型的变量可以存储任意的实现这个方法集合的类型,这种类型是此interface的超集。这种类型被称为实现了接口。接口类型的变量如果未初始化则它的值为nil。
在Go 1.18中,interface定义改变了:
An interface type defines a type set. A variable of interface type can store a value of any type that is in the type set of the interface. Such a type is said to implement the interface. The value of an uninitialized variable of interface type is nil.
接口类型定义了一个类型集合。接口类型的变量可以存储这个接口类型集合的任意一种类型的实例值。这种类型被称之为实现了这个接口。接口类型的变量如果未初始化则它的值为nil。
所以一句话,先前接口定义了方法集合,现在接口定义了类型集合。接口的用途也进行了扩展。
interface的定义也扩展了。先前,接口定义只能包含方法元素(method element):
|
|
现在接口定义除了方法元素外,还可以包含类型元素:
|
|
类型元素包含类型(T
)或者近似类型(~T
)或者联合(union)元素(A|B|C|~D
)。
但是,因为接口的定义和含义改变了,所以接口在使用的时候也有一些些不同。本文通过实例一一介绍。
首先记住一点,Go 1.17.x 及以前的版本中接口的使用方法在Go 1.18中照样使用,使用方法不变。变得是接口有类型元素或者做类型约束时的一些限制。
近似元素的类型T
必须是底层类型(underlying type)自己,而且不能是接口类型
|
|
联合(union)类型元素不能是类型参数(type parameter)
|
|
|
|
联合(union)类型元素的非接口元素必须是两两不相交
两两不相交意思是两两的交集是空集,比如 int|string
的交集是空集,而int|~int
的交集是int
。
联合类型中的非接口元素必须是两两不相交的。
下面的定义没问题,因为any等价于interface{}
:
|
|
|
|
联合(union)类型元素如果包含多于一个元素,不能包含包含非空方法的接口类型,也不能是comparable或者嵌入comparable
这条规则定义了接口作为类型元素的一些限制.
|
|
包含非接口类型元素、近似元素和联合类型只能用作类型参数,或者其它用作约束接口的元素
|
|
接口类型不定递归嵌入
|
|