接口
在go语言中,也可以定义接口类型。我们都知道,在面向对象的程序语言中,接口是实现多肽的必要条件。我们可以通过接口来接收不同的实现。go语言中通过interface关键字来定义接口。
//定义一个Reader接口
type Reader interface{
//定义接口方法
read()
}
复制代码
上面定义了一个接口,那么如何来实现接口呢?在go语言中,可以在自定义的类型中通过方法来实现接口。我们来一个例子:
package main
import (
"fmt"
)
//定义一个Reader接口
type Reader interface{
//定义接口方法
read()
}
//自定义类型
type FileReader struct{
fileName string
fileSize int
}
//实现Reader接口
func (fr FileReader) read(){
fmt.Println("来自FileReader实现。。")
}
func main(){
//使用接口类型接收
var reader Reader = FileReader{fileName:"data.txt",fileSize:1024}
//调用接口方法
reader.read()
fmt.Println("mian函数执行完成")
}
//来自FileReader实现。。
//mian函数执行完成
复制代码
从上面的代码我们可以看到,go语言中实现接口的方式比较特别,它是通过实现对应接口的方法来达到实现接口的目的,从而可以使用接口类型来接收具体的实现类型,也就具有了多肽特性。
再来看一个复杂点的例子:
package main
import (
"fmt"
)
//定义一个Reader接口
type Reader interface{
//定义接口方法
read()
}
//自定义类型
type FileReader struct{
fileName string
fileSize int
}
type JsonReader struct{
total int
}
//实现Reader接口的方法
func (fr FileReader) read(){
//修改fileName
fr.fileName = "new name";
fmt.Println("来自FileReader实现。。")
}
//实现Reader接口的方法,使用JsonReader指针作为接收者
func (jr *JsonReader) read(){
jr.total = 101
fmt.Println("来自JsonReader的实现")
}
func startReader(reader Reader){
fmt.Println("开始执行read方法")
reader.read()
fmt.Println("read方法执行结束")
}
func main(){
fr := FileReader{fileName:"data.txt",fileSize:1024}
//注意这里,使用的是指针
jr := JsonReader{total:100}
startReader(fr)
fmt.Println("fileName=",fr.fileName)
startReader(&jr)
fmt.Println("total=",jr.total)
fmt.Println("mian函数执行完成")
}
//开始执行read方法
//来自FileReader实现。。
//read方法执行结束
//fileName= data.txt
//开始执行read方法
//来自JsonReader的实现
//read方法执行结束
//total= 101
//mian函数执行完成
复制代码
上面的代码,新增加了JsonReader类型,它也实现了Reader接口。但是有一点不同,JsonReadr在实现Reader接口的时候,使用的是指针作为方法的接收者。而FileReader是使用值作为方法的接收者。那么这两种方式有什么不同呢?
通过上面的代码可以看出,在实现的read方法内部,修改实现的属性,使用值做为接收者的时候,属性修改不成功,这是因为值传递的是一个副本,对副本的修改不会影响值的本身。而使用指针作为接收者的时候,对属性的修改都会体现在对应的对象上面。
startReader函数的参数类型是Reader类型,并不是指针,那么为什么在startReader(jr) 的时候,将指针类型传递给它,函数也能正常执行呢?
在go语言中:
如果使用指针接收者来实现一个接口,那么只有指向那个类型的指针才能够实现对应的接口。 如果使用值接收者来实现接口,那么那个类型的值和指针都可以实现对应的接口。
上面的两句是什么意思呢,对比上面的代码来说。 startReader(fr)可以改成startReader(&fr),程序同样可以正确运行,但是结果一样。
startReader(&jr)不能改成startReader(jr),否者编译会报错。