接口在Go语言中很特殊的编程特色。在各种面向对象语言中,都有接口的定义与使用。接口其实就是对某些方法的约定。每个接口只是需要定义相应的方法,而不需要实现这个方法。接口中的方法就是由implements该接口的类来实现接口中的方法。
比如说我定义一个move(活动)接口,在这个接口中有fly(飞),walk(走),swim(游)三种方法。那么至于实现哪个具体的方法,就有实现move接口的类来决定。比如说我用fish类实现move接口,我只要去具体实现swim方法就可以了 。
使用过java的同学应该对接口(interface)关键字比较熟悉。如果某个类要实现这个接口,就必须显式声明即用implements来标识。
在Go语言中接口有着其特殊的特点:
比如说我定义一个接口Retriever,在这个接口中有个Get方法 :
type Retriever interface {
Get(url string) string
}
那么如果我在某个函数(使用者)使用(定义)一个接口:
func download(r Retriever) string {
return r.Get("http://www.baidu.com")
}
为什么说接口是由使用者定义呢?在上面的download函数中,我们定义了一个Retriever的r。至于是谁实现的这个r根据传入的实现者决定,也就是说。使用者只使用方法。实现者也只负责实现方法。至于对应的接口是哪个只有在定义接口的时候知道
比如我用Retriever.go
package real
import (
"time"
"net/http"
"net/http/httputil"
)
type Retriever struct {
UserAgent string
TimeOut time.Duration
}
func (r *Retriever) Get(url string) string{
resp ,err := http.Get(url)
if err !=nil {
panic(err)
}
//resp.Body.Close()
result,err := httputil.DumpResponse(resp,true)
if err!=nil{
panic(err)
}
return string(result)
}
来实现Get方法,在这里我们看到,定义的接收者是一个指针接收者。实现了Get方法,我们只是实现了Get方法。并不需要像java那样implement某个接口,只是指定接口中的方法就可以了。所以说:
在实现某个接口接收者既可以是指针接收者,也可以是值接收者。
那么我们定义一个接口以后,得到一个接口变量,在变量中都有什么呢?
我们可以对已实现的接口变量进行输出查看
fmt.Printf("%T %v",r,r)
会看到r的type和r的实际内容。
同样,我们如果想要根据接口的类型来区分,可以用上图的几种方法。
switch v := r.(type) {
case *mock.Retriever:
fmt.Println("Contents:",v.Contents)
case *real2.Retriever:
fmt.Println("UserAgent",v.UserAgent)
}
//Type assertion
realRetriever := r.(*real2.Retriever)
fmt.Println(realRetriever.TimeOut)
if mockRetriever , ok := r.(*mock.Retriever);ok{
fmt.Println(mockRetriever.Contents)
}else {
fmt.Println("not a mock retriever")
}
当然接口可以进行组合,定义出新的接口
type RetrieverPoster interface {
Retriever
Poster
}
常用的系统接口有String(),类似于java中的tostring()方法
func (r *Retriever) String() string {
return fmt.Sprintf(
"Retriever :{contents = %s}",r.Contents)
}
再就是比较常用的read,write。详细的实际项目进行使用