参考:
http://c.biancheng.net/view/78.html
关键点
通过关键词汇
,实现快速
理解,记忆
的目的
:
1、实现
接口
的类型
要求?或者说,哪些
类型可以实现
接口?
非接口
类型,可以实现接口
接口
类型,同样
也可以实现接口2、Go语言中
两个
类型之间
的实现
关系?
是通过Go语言编译器
自动 检查的,无须显示
的表明,如无须通过implement
关键字来表示3、Go语言中的
接口
跟其他语言中的接口如Java,有什么区别
?A、如
Java
中存在派生式
接口,类型间存在强耦合
的父子
关系,可能存在很复杂
的“派生树”
B、而Go语言中,
非侵入式
设计让实现者
的所有类型
均是平行
的、组合
的;不需要
同时也不可能有“类派生图”
,开发者
唯一需要关注
的就是“我需要什么?”
,以及“我能实现什么?”
。4、既然Go语言中
没有显示
的表明类型实现
了哪个
接口,那么Go语言是如何
来做的呢?隐式
A、接口
被实现
的条件一:接口的方法
与实现接口的类型方法
格式一致
B、接口被实现的条件
二
:接口中所有方法均被
实现
接口定义后,需要实现接口,调用方才能正确编译通过并使用接口。
接口
的实现
需要遵循两条
规则才能让接口
可用。
1、接口被实现
的条件一:接口的方法
与实现接口的类型方法
格式一致
在类型中添加与接口签名一致的方法就可以实现该方法。
签名包括方法中的名称
、参数列表
、返回参数列表
。
也就是说,只要实现接口类型中的方法的名称、参数列表、返回参数列表中的任意一项与接口要实现的方法不一致,那么接口的这个方法就不会
被实现。
为了抽象数据写入的过程,定义 DataWriter 接口来描述数据写入需要实现的方法,接口中的 WriteData() 方法表示将数据写入,写入方无须关心写入到哪里。实现接口的类型实现 WriteData 方法时,会具体编写将数据写入到什么结构中。这里使用file结构体实现 DataWriter 接口的 WriteData 方法,方法内部只是打印一个日志,表示有数据写入,详细实现过程请参考下面的代码。
数据写入器的抽象:
package main
import (
"fmt"
)
// 定义一个数据写入器
type DataWriter interface {
WriteData(data interface{}) error
}
// 定义文件结构,用于实现DataWriter
type file struct {
}
// 实现DataWriter接口的WriteData方法
func (d *file) WriteData(data interface{}) error {
// 模拟写入数据
fmt.Println("WriteData:", data)
return nil
}
func main() {
// 实例化file
f := new(file)
// 声明一个DataWriter的接口
var writer DataWriter
// 将接口赋值f,也就是*file类型
writer = f
// 使用DataWriter接口进行数据写入
writer.WriteData("data")
}
代码说明如下:
- 第 8 行,定义 DataWriter 接口。这个接口只有一个方法,即 WriteData(),输入一个 interface{} 类型的 data,返回一个 error 结构表示可能发生的错误。
- 第 17 行,file 的 WriteData() 方法使用指针接收器。输入一个 interface{} 类型的 data,返回 error。
- 第 27 行,实例化 file 赋值给 f,f 的类型为 *file。
- 第 30 行,声明 DataWriter 类型的 writer 接口变量。
- 第 33 行,将 *file 类型的 f 赋值给 DataWriter 接口的 writer,虽然两个变量类型不一致。但是 writer 是一个接口,且 f 已经完全实现了 DataWriter() 的所有方法,因此赋值是成功的。
- 第 36 行,DataWriter 接口类型的 writer 使用 WriteData() 方法写入一个字符串。
运行代码,输出如下:
WriteData: data
本例中调用及实现关系如下图所示。
当类型无法实现接口时,编译器会报错,下面列出常见的几种接口无法实现的错误。
1) 函数名
不一致导致的报错
在以上代码的基础上尝试修改部分代码,造成编译错误,通过编译器的报错理解如何实现接口的方法。首先,修改 file 结构的 WriteData() 方法名,将这个方法签名(第17行)修改为:
func (d *file) WriteDataX(data interface{}) error {
编译代码,报错:
cannot use f (type *file) as type DataWriter in assignment:
*file does not implement DataWriter (missing WriteData method)
报错的位置在第 33 行。报错含义是:不能将 f 变量(类型file)视为 DataWriter 进行赋值。原因:file 类型未实现 DataWriter 接口(丢失 WriteData 方法)。
WriteDataX 方法的签名本身是合法的。但编译器扫描到第 33 行代码时,发现尝试将 *file 类型赋值给 DataWriter 时,需要检查 *file 类型是否完全实现了 DataWriter 接口。显然,编译器因为没有找到 DataWriter 需要的 WriteData() 方法而报错。
2) 实现接口的方法签名
不一致导致的报错
将修改的代码恢复后,再尝试修改 WriteData() 方法,把 data 参数的类型从 interface{} 修改为 int 类型,代码如下:
func (d *file) WriteData(data int) error {
编译代码,报错:
cannot use f (type *file) as type DataWriter in assignment:
*file does not implement DataWriter (wrong type for WriteData method)
have WriteData(int) error
want WriteData(interface {}) error
这次未实现 DataWriter 的理由变为(错误的 WriteData() 方法类型)发现
WriteData(int)error,期望 WriteData(interface{})error。
这种方式的报错就是由实现者的方法签名与接口的方法签名不一致导致的。
2、接口被实现的条件二
:接口中所有方法均被
实现
当一个接口中有多个方法时,只有这些方法都被
实现了,接口才能被正确编译并使用。
在本节开头的代码中,为 DataWriter中 添加一个方法,代码如下:
// 定义一个数据写入器
type DataWriter interface {
WriteData(data interface{}) error
// 能否写入
CanWrite() bool
}
新增 CanWrite() 方法,返回 bool。此时再次编译代码,报错:
cannot use f (type *file) as type DataWriter in assignment:
*file does not implement DataWriter (missing CanWrite method)
需要在 file 中实现 CanWrite() 方法才能正常使用 DataWriter()。
3、接口类型
实现接口
上面介绍的是通过普通类型来实现接口, 下面使用接口来实现接口;或则说接口内嵌接口:
package main
import "fmt"
type TextWriter interface {
TextDataWrite(data interface{})
}
type FileWriter interface {
TextWriter
FileDataWrite(data interface{})
}
type file struct {
}
func (f file)FileDataWrite(data interface{}) {
fmt.Printf("hello %v\n", data)
}
func (f file)TextDataWrite(data interface{}) {
fmt.Printf("hello %v\n", data)
}
func main() {
f := new(file)
var fw FileWriter
fw = f
fw.FileDataWrite("file data write")
fw.TextDataWrite("text data write")
}
4、通过接口内嵌
实现复杂
接口
注意:
如果
手机端
,不能
查看效果
的话,可以
通过电脑网页
查看。