Go 中的 interface type (浅显理解)
Go 的设计确实很惊艳,不愧为「 21 世纪的 C 语言」。
Go 是静态强类型的,也就是说,在编译时会检查所有变量是否声明了类型,所有函数声明中形参是否声明了类型、返回值是否空、返回非空的话是否声明了类型,所有出现的函数调用中参数类型是否匹配、返回类型是否匹配并成功返回。
非常的严格到位,和 C 一样。
但类型的动态化又是一个必须得到满足的需求。在任何一门语言(至少我接触过的)中,这个问题都得到了解决, C 语言也不例外。
C 利用 void* 指针搭配 malloc() 函数,可以解决一切动态问题,无论是动态数据,还是动态方法,毕竟它们本质上都是一堆内存里的数据,而内存一旦被分配,我们就可以通过内存的地址(指针的值就是地址)索引到内存数据。
但 C 提供的太过底层,不够抽象,导致工程量很大,还很容易出错,尤其是对我这种水平弱鸡的程序员来说。
在这之后的语言,都有各自的解决办法。
Go 给出的 interface type 的解决方法特别惊艳。
interface 是一种数据类型,但这种数据类型存放的不只是所谓的数据,还有关于数据的类型以及绑定到数据之上的方法。
在 Go 中,数据和方法分离的很彻底:
数据可以通过 struct 类型自定义,并通过给函数指派接收者的方式给某一个数据类型绑定方法。当然,数据类型是可以嵌套定义的,方法随之被嵌套。
在这之后,就是 interface 发挥威力的时候了:interface type 可以凌驾在任何数据类型之上。
在这里, interface type 并不是某一个数据类型,而是「一大类」数据类型。这一大类数据类型的不同之处在于:包含的方法不同。
- interface{} 最简单,无任何方法。所以在 Go 中,任何数据类型都可以被包含在 interface{} 当中。也就是说,任何数据都可以被声明为 interface{} type,注意,是任何数据被声明为 interface{} type。
- 在此基础之上,通过给 interface 指定方法,可以定义「某一种类型」。任何包含指定方法的数据都可以被赋值给这种 interface 类型。
通过方法,可以在编译时检查静态类型是否匹配,并可以在运行时,动态检查并提取。
如何动态检查并提取呢?任何一种 interface 类型都会维护两方面的内容:
- 数据
- 方法列表,并且默认有一个方法可以返回 interface 所存「数据」的数据类型,以及 interface 类型本身自己的方法列表,以及这个列表当中的方法在所存「数据」的数据类型中的具体实现。当然,这些都通过指针指向完成,interface 本身并不会存储太多东西
通过这种方式,interface 有什么好处呢?
- 可以提前设计某一类数据类型的通用数据接口,定义更具体的数据类型时再实现接口。这是先有高层抽象设计再有具体实现。
- 也可以统摄已经存在的某一类具有共同通用接口的数据类型。这是先有实现再有高层抽象。
- 混合使用,可以中途添加新设计的高层抽象,也可以中途添加总结出来的高层抽象。
- 也就是说,这个 interface 在实现代码高内聚、松耦合上,特别顺手。
在 interface 的作用下,我们终于可以在静态和动态之间取得一个十分良好的平衡:
- 传统的静态,诸如 C++ 、 Java ,提供「泛型」机制以及其它一些机制来让使用者实现数据传递的类型动态化和函数方法的绑定动态化。但这些机制一方面太过分散,另一方面功能也很弱,不好用,还不好管理。
- 传统的动态,诸如 Python 、 JS,提供了特别强大的运行时调用机制,十足的鸭子类型。但这种机制显得太过灵活,提供的能力太大,而使用者大部分时候用不上,使用的时候大多也不懂其内部具体机制,不好排查问题。
差不多把我目前理解的 interface 全部讲出来了,浅显的很,但确实比 Java 丰富,比 Python 和 JS 来,机制也更清晰明了,虽然内部具体实现还是不清楚,但至少可以使用「指针」这个集抽象和具体操作于一体的概念进行一个脉络式把握。
补遗
interface 类型中的数据,不能直接拿到,而且不能通过直接的类型转换得到。
Go 提供了两个方法:
- type assertion
- with ok or not
- value := anyInterface.(T) or value, ok := anyInterface.(T)
- type switch
- used to implement dynamic type task
总结特点的话:
- 类型断言旨在拿到 ADT 内部的真实数据
- 类型开关旨在调用 ADT 内部的方法
- 当然,也可以在恰当的时候灵活使用
不知是该恭喜,还是该怎样,总之阅读到该文的,你是第 人。每一次刷新,都是不同的自己。