type
status
date
slug
summary
tags
category
icon
password
历史回顾
简单来讲,在go1.20之前,any类型的参数是不可以传给comparable类型的参数的,
比如以下代码
但在go1.20中,对接口实现 与 约束满足 的具体定义做出了一点小小的区分,使得这一做法可行。
概念理解
要想弄清楚背后的具体机制,首先我们来理解一些概念:
- 类型参数:Go1.18 引入泛型时所产生的新名词,一个方法接受的那个参数,其值所在的集合被类型参数所约束;
- 类型约束:类型约束定义了允许作为类型参数的类型集。
- comparable: Go定义的可比较的定义是支持==,但是comparable这一interface并不包含所有comparable的类型,因为作为一个接口,它并不包含任何接口,而像any这样的接口是满足comparable的定义的;
接口实现与类型约束
go1.18出现的概念甚至可以改变我们看待interface的角度:原先interface被认为是方法的集合,而现在,我们可以将其看作类型的集合,这个集合中的每一个类型都满足了这些方法。
除了上面说的隐式类型,显式的也是可以的;
比如下面这个:
这个interface定义了一组底层类型为int或是int64且实现了print方法的类型。
有了新的视角,我们还需要一种新的方法来解释实现接口的含义。如果 T 是接口类型集的一个元素,我们就说一个(非接口)类型 T 实现了接口 I。如果 T 本身是一个接口,它就描述了一个类型集。该集合中的每个类型也必须在 I 的类型集合中,否则 T 将包含不实现 I 的类型。因此,如果 T 是一个接口,那么如果 T 的类型集是 I 的类型集的子集,它就实现了接口 I。
而对于类型约束,在go1.20以前,我们认为就是类型需要实现某一个接口,这种做法能带来好处,比如防止出现传给comparable类型的参数的any变量变成数组这一类不可hash的类型,出现run-time error;
但是,这也削弱了go的泛型能力,由于类型严格的约束,我们不能将any类型的变量传递给comparable,毕竟后者是前者的子集,说明前者并未实现后者。
Go1.20做出的概念调整
go1.20的做法是对 接口实现 与 类型约束 这两个概念 做出了一些细微的改变:
A type
T
satisfies a constraint C
ifT
implementsC
; or
C
can be written in the forminterface{ comparable; E }
, whereE
is a basic interface andT
is comparable and implementsE
.
如此,我们发现,对于any来说,由于它是comparable的(支持==),因此它可以被当作comparable变量使用。
我们来看下面这个例子:
可以看到,go1.20中,any变量给comparable参数已经不会报错了;
TYPE SAFE问题与解决方案
而这种改变也带来一个问题,comparab不再是type safe,因为错误any可能传入并非comparable的变量,由于编译时不会有错误,那么就会出现运行时panic;
解决方案如下:
- 作者:Alex
- 链接:https://nextme.one/wureny.eth/article/gocomany
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。