Go 语言基础 - 接口
Go 语言没有类与继承的概念,但它提供的「接口」功能,也能让我们优雅地实现面向对象的特性。
在许多面向对象语言中,接口定义完之后,要实现一个接口,需要显示写明,比如Java
使用implements
关键字来实现接口。
而 Go 语言中的接口是隐式的,非侵入性实现,方便又灵活。
它允许我们提供新的接口类型,却无需改动到旧的实现代码。
接口的定义者,只需要定义好接口内容,不需要知道会被哪些类型实现。而接口的实现者,也只需要知道实现了哪个接口,不用显示指明。
声明(定义)接口
通过关键字type
和interface
,可以定义接口,接口可以包含一个或数个方法声明。
对于方法声明,跟普通方法一样,只是它不需要提供实现,另外方法的参数名以及返回值的名称可以写也可以不写。
比如我们常用的fmt
包中,就有这么一个接口:
1 | type Stringer interface { |
Stringer
是接口的名称,它拥有一个String() string
的方法。
如何实现接口
要对接口进行实现,需要满足两个条件
- 实现的接口方法,签名必须一致,也就是方法的「名称」、「参数列表」,「返回值列表」都得一致;
- 实现了接口的所有方法。
只要同时符合上述两个条件,类型便实现了接口。
还是以Stringer
接口为例,只要类型实现了String() string
方法,那么它就可以被当成Stringer
使用。
在fmt
的输出中,有这么一段代码:
1 | // If a string is acceptable according to the format, see if |
上面代码涉及到接口的断言,后续会说明
在代码中,fmt
包通过类型判断输出的对象是否属于Stringer
,如果是的话,会调用它的String()
方法。
我们现在提供Person
类型,实现了String() string
,看看它的效果:
1 | type Person struct { |
运行后能看到输出为:1
Person: Justin
说明Person
是被当成Stringer
使用的。
类型与接口的关系
因为 Go 中的接口与实现是隐式关系,这带来了极大的灵活性:
- 一个类型可以同时实现多个接口,而且接口之间可以完全没有关系,相互独立;
- 在不改动原有类型的代码的基础上,我们可以提取出新的接口。
比如现在有一组类型,它们都拥有func Fly()
,那我们可以提取出:
1 | type Flyer interface { |
那原有的拥有Fly方法的类型,都可以被当成Flyer使用。
类型断言
有时候我们想把接口转换成具体的类型或者其他接口,可以使用类型断言:
1 | value, ok := x.(T) |
效果是将x
转换成具体类型T
。
假设转换成功,那么value
将会被赋值,类型是T
,同时ok
值为true;如果失败了,那value
不会被赋值,ok
值为false。
我们可以不接收ok
的值,比如:
1 | value := x.(T) |
转换效果与接收ok
是一致的,不同点在于,假设转换失败,那么程序会直接panic
。
switch
还可以配合.(type)
一起使用,针对具体的类型,做出不同的逻辑处理。
1 | func assertType(i interface{}) { |
接口嵌套
类型可以嵌套,接口也可以嵌套。
比如Go语言的io包中,有这么几个接口:
1 | type Reader interface { |
它们可以组合成各种各样的接口:
1 | // ReadWriter is the interface that groups the basic Read and Write methods. |
当一个类型既实现了Reader
,也实现了Writer
,那么它便是ReadWriter
,以此类推。
有了这个特性,我们在定义跟使用接口时也更为灵活,每一项特性都可以是一个小的interface
,多个接口可以组合成新的接口。
空接口
空接口是指没有任何方法的接口,它是接口的特殊形式,所有类型都属于空接口。
它类似于 Java 中的 Object,C语言的 void*,TypeScript 中的 any。有需要它的场景,但不能滥用。
首先我们看看空接口可以怎么接收参数。
1 | type Person struct { |
我们定义了一个show
函数,入参为entry interface{}
,它可以接收任何参数并将其打印出来。
那我们要怎么从空接口来获取具体类型?
答案是 使用断言。
比如:
1 | var a interface{} = 100 |
记得断言可以有两个接收参数,第二个参数是判断是否转换成功用的。
总结
本文介绍了interface
(接口)的使用方式,包括:
- 如何声明定义接口
- 如何实现接口
- 接口与类型直接的关系
- 接口断言
- 接口嵌套
- 特殊的接口形式:空接口
基本上可以涵盖日常对接口的使用,Go 的接口使用方便简洁,隐式的实现让我们可以实现对代码的非侵入性,不需要使用类似于Java
中的implements
关键字。
- 本文链接:https://keepmoving.ren/golang/interface/
- 版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!