Golang | 接口

接口

接口是一个或者多个方法签名的集合,任何类型 只要实现一个集合的全部方法,就表示这个类型实现了这个接口,并且无需在类型上显式的添加接口声明。

  • 接口命名一般以 er结尾
  • 接口只有方法签名,没有实现
  • 接口没有数据字段
  • 可以在一个接口中嵌入其它接口
  • 一个类型可以实现多个接口

空接口没有方法签名,意味着任何类型都实现了 interface{}

接口的内部结构

struct Iface{
  Itab* tab;		// 接口表
  void* data;		// 数据指针
};
struct Itab{
  InterfaceType* inter;
  Type* type;
  void (*fun[])(void);
};

接口表中存放着元数据信息,接口类型,动态类型,接口实现的方法指针。

数据指针中存放的是目标对像的只读复制品,复制完整对象或指针。

接口的使用

模拟一个场景,我们现在需要获取两个网站的数据,对这两个数据进行不同的处理,返回的数据格式是一样的。

代码结构:

image-20220404033243982

// interfa_example.go
package main

// 定义一个接口,只有 Get 方法
type Requester interface {
	Get(string) string
}

func download(r Requester,url string) string {
	return r.Get(url)
}

func main() {
	rs := sogou.Request{}
	fmt.Println(download(rs,""))
	rb := baidu.Request{}
	fmt.Println(download(rb,""))
}

// sogou.request.go
package sogou

type Request struct {}

func (r Request) Get(s string) string {
	resp, _ := http.Get("https://www.sogou.com")
	defer resp.Body.Close()

	body, err := httputil.DumpResponse(resp, true)
	if nil != err {
		panic(err)
	}
	return string(body[100:])
}

// baidu.request.go
package baidu

type Request struct {}

func (r Request) Get(s string) string {
	resp, _ := http.Get("https://www.baidu.com")
	defer resp.Body.Close()

	body, err := httputil.DumpResponse(resp, true)
	if nil != err {
		panic(err)
	}
	return string(body[:100])
}

非常简单的一个实现,在这里我对两个实现进行了稍微不同的处理,一个是只取前100个字符,一个是只取100个之后的字符。

在这个实现中,我们可以看到,我们相切换请求的话,只需要改一个包名就可以请求不同的网站了。这里就是使用了接口。

并且我们在实现类上面也没有显式的实现接口,只是实现接口的方法就说明这个结构体实现了这个接口。

接口组合

现在又改变需求了,不光要求我们要获取不同的网站数据了,还需要我们使用 POST 请求别的数据。

// interfa_example.go
type session interface {
  Requester
  Post() string
}
// baidu.request.go
func (r Request) Post() string {
	return "baidu"
}
// sogou.request.go

func (r Request) Post() string {
	return "sogou"
}

在不破坏代码原有结构的前提下,我们在以上文件中增加以这些代码后,就实现了这个需求了,这里就使用了接口的组合特性。

接口类型判断

接口判断有两方法:

	// if 判断
	if rb,ok := r.(baidu.Request); ok{
		fmt.Println(rb.Post())
	}else{
		fmt.Println(rb.Post())
	}

	// switch 无法使用 fallthrough
	switch r.(type) {
	case baidu.Request:
		fmt.Println("baidu")
	case sogou.Request:
		fmt.Println("sogou")
	}


关注公众号,随时获取最新资讯

细节决定成败!
个人愚见,如有不对,恳请斧正!

posted @ 2022-04-04 05:35  一点浩然气~  阅读(81)  评论(0编辑  收藏  举报