写在前面
在上一篇文章《Golang入门学习之方法(method)》当中,我们学习了Golang当中的方法的定义与运用,在接下来的这篇文章当中,我们将一起来学习Goalng的接口(interface)。
接口的定义
接口是定义了一组需要被实现的方法的抽象类型,实现接口的数据类型可以视为接口的实例。接口由一组方法与一个接口类型组成。声明格式如下:
1 | type 接口名 interface{ |
按照Golang的编程风格(约定),只包含一个方法的接口的名字由方法名加 [e]r
后缀组成,例如 Printer
、Reader
、Writer
、Logger
、Converter
等等。还有一些不常用的方式(当后缀 er
不合适时),比如 Recoverable
,此时接口名以 able
结尾,或者以 I
开头(像 Java
中那样)。
Go 语言中的接口都很简短,通常它们会包含 0 个、最多 3 个方法。
请看下面这个例子:
首先,我们在interfaces包中声明一个SpiritualRootAble
(表示具备修行的能力,现了灵根接口的凡人即可修炼)接口
src/go_code/interface/interfaces/spiritual_root.go
1 | package interfaces |
其次,我们在model包当中声明一个凡人结构体(mortal
) 并实现SpiritualRootAble
接口
src/go_code/interface/model/mortal.go
1 | package model |
最后,我们在main中使用他们
src/go_code/interface/main/main.go
1 | package main |
输出:
1 | 火灵根 |
可以看到:
在Golang中并需要显示地声明类型实现了某一接口(不需要如同Java那样class implemments interfacesName
),只要类型实现了接口当中定义的方法集,类型即是实现了该接口。
实现某个接口的类型(除了实现接口方法外)可以有其他的方法。
一个类型可以实现多个接口(实际上mortal
还实现了空接口,关于空接口的内容请继续往下看)。
接口类型可以包含一个实例的引用, 该实例的类型实现了此接口(接口是动态类型)。
空接口
空接口即为不包含任何方法的接口。任何类型都实现了空接口。空接口有点类似于Java当中的Object的概念
1 | type Any interface {} |
接口嵌套接口
一个接口可以包含一个或多个其他的接口,这相当于直接将这些内嵌接口的方法列举在外层接口中一样。
比如接口 File
包含了 ReadWrite
和 Lock
的所有方法,它还额外有一个 Close()
方法。
1 | type ReadWrite interface { |
Golang中的类型断言
对于一个接口类型变量varI
中可以包含任何类型的值,so,必须有一种方式来检测它的动态类型,也就是运行时变量var中存储的值的实际类型。而这,就是类型断言。
1 | v := varI.(T) |
类型断言可能是无效的,虽然编译器会尽力检查转换是否有效,但是它不可能预见所有的可能性。如果转换在程序运行时失败会导致错误发生。更安全的方式是使用以下形式来进行类型断言:
1 | if v,ok :=varI.(T);ok{ |
如果转换合法,v
是 varI
转换到类型 T
的值,ok
会是 true
;否则 v
是类型 T
的零值,ok
是 false
,也没有运行时错误发生。
如果我们只是需要判断varI
是否为T类型而不需要获取类型T的值时,可以这样做:
1 | if _,ok := varI.(T);ok{ |
我们继续沿用上面的例子讲类型断言这部分的内容
1 | package main |
输出:
1 | &{韩立 男性 金灵根 1} |
值得注意的是,我们在实现SpiritualRootAble
时方法的receiver类型为*Mortal
,即凡人的指针类型。因此实际上实现SpiritualRootAble接口的是*Mortal,因此在进行类型断言时T为*Mortal
。我们在使用类型断言的时候要注意这一点,不然编译器会报错。
类型断言的应用
在Golang中,我们如何测试一个值是否实现了某一接口呢?答案就是通过类型断言
1 | var m interfaceTypeName |
总结
接口可以理解为一种契约,实现类型必须满足它,它描述了类型的行为,规定类型可以做什么。接口彻底将类型能做什么,以及如何做分离开来,使得相同接口的变量在不同的时刻表现出不同的行为,这就是多态的本质。
在golang中:
- 指针方法可以通过指针调用
- 值方法可以通过值调用
- 接收者是值的方法可以通过指针调用,因为指针会首先被解引用
- 接收者是指针的方法不可以通过值调用,因为存储在接口中的值没有地址
将一个值赋值给一个接口时,编译器会确保所有可能的接口方法都可以在此值上被调用,因此不正确的赋值在编译期就会失败。
写在最后
关于Golang当中接口的知识点我就简单介绍到这里。本文当中涉及到的例子可以点击此处下载。如果我的学习笔记能够给你带来帮助,还请多多点赞鼓励。文章如有错漏之处还请各位小伙伴帮忙斧正。从下一篇文章开始,我们将开启筑基系列的学习,具体涉及到的知识点有:反射、文件操作、数据交换、错误处理、Go协程(goroutine)和通道(channel)等内容。欢迎各位小伙伴订阅我的博客👊。