GO 面向接口理论与实践

1、duck typing的概念

1.1 接口

相比较传统语言来说,go语言的接口更加的灵活

type Traversal interface{
  Traverse()
}

func main(){
  traversal := getTraversal()
  traversal.Traverse()
}

1.2 duck typing概念

  • “像鸭子走路,像鸭子叫(长的像鸭子),那么就是鸭子”

  • 描述事物的外部行为而非内部结构

  • 要从使用者的角度来看

  • 严格说go属于结构化类型系统,类似duck typing

1.2.1 python中的duck typing

def download(retriever):
  return retriever.get("pfeiwang.blog.csdn.net")
  • 运行时才知道传入的retriver有没有get方法
  • 需要注释来说明接口

1.2.2 c++中的duck typing

通过模版来支持

template <class R>
string download(const R& retriever){
  return retriever.get("pfeiwang.blog.csdn.net");
}
  • 编译时才知道传入的retriever有没有get
  • 徐阿哟注释来说明接口

1.2.3 java中的类似代码

<R extends Retriever>
String download(R r){
  return r.get("pfeiwang.blog.csdn.net");
}
  • 传入的参数必须实现Retriever接口
  • 不是duck typing

1.2.4 go中的duck typing

  • 同时需要Readable、Appendable怎么办?(apache polygene)
  • 同时具有python、c++的duck typing的灵活性
  • 又具有java的类型检查

2、接口的定义和实现

Created with Raphaël 2.2.0 使用者 download 实验者 retriever
  • 接口由使用者定义

2.1 接口的实现

  • 接口的实现是隐式的
  • 只需要实现接口里的方法
目录结构如下:
retriever
	mock
		mockretriever.go
		real.go
	main.go
// main.go
package main
import (
	"fmt"
	"retriever/mock"
)

type Retriever interface{
	Get(url string) string
}

func download(r Retriever) string{
	return r.Get("http://pfeiwang.blog.csdn.net")
}

func main(){
  // Retriever_struct来自于mockretriever.go,Retriever来自于real.go,一个是可以真实下载的,一个是fake
	//r := mock.Retriever_struct{"hello world"}
	retriever := mock.Retriever{}
	fmt.Println(download(retriever))
}
// mock/mockretriever.go
package mock

type Retriever_struct struct{
	Constents string
}

func (r Retriever_struct) Get(url string) string{
	return r.Constents
}
// mock/real.go

package mock

import (
	"net/http"
	"net/http/httputil"
	"time"
)

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)
	}

	request, err := httputil.DumpResponse(resp, true)

	resp.Body.Close()

	if err != nil{
		panic(err)
	}
	return string(request)
}

3、接口的值类型

3.1 接口变量里面有什么?

  1. 接口变量自带指针
  2. 接口变量同时采用值传递,几乎不需要使用接口的指针
  3. 指针接收者实现只能以指针方式使用;值接收者都可

文件内容同2.1那么var r Retriever的r是值类型,但是他的内部是什么样子的呢?

fmt.Printf("%T %v\n", r, r)

其中%T表示输出r的类型,%v表示输出r的值

mock.Retriever {this is a fake pfeiwang.blog.csdn.cn}
real.Retriever { 0s}

此时,如果将Retriever的接收者改为指针接收者

func (r *Retriever) Get(url string) string{
	resp, err := http.Get(url)
	if err != nil{
		panic(err)
	}

	request, err := httputil.DumpResponse(resp, true)

	resp.Body.Close()

	if err != nil{
		panic(err)
	}
	return string(request)
}

那么,声明变成

var r Retriever

r = &real.Retriever{
  UserAgent: "mother",
  TimeOut: time.Minute,
}

此时使用fmt.Printf("%T %v\n", r, r),得到如下输出

*real.Retriever &{mother 1m0s}

3.2 获取接口里面的类型

switch v := r.(type){
case mock.Retriever:
  fmt.Println("contents", v.Contents)
case *real.Retriever:
  fmt.Println("UserAgent", v.UserAgent)
}

3.2.1 type assertion(类型断言)

上面的r.(type)就是一个类型断言

还有一种使用方式https://segmentfault.com/a/1190000012495480

realRetriever := r.(*real.Retriever)

如果r是*real.Retriever类型的返回这个类型,不然的话会panic,但是要用下面更加合理的方式进行coding

if curRetriever, ok := r.(mock.Retriever); ok{
  fmt.Println(curRetriever.Contents)
} else{
  fmt.Println("not a mock retriever")
}

3.2.2 查看接口变量

  • 表示任何类型: interface{}
  • Type Assertion
  • Type Switch

例子:下面的queue可以推入任何类型的元素

package queue

type Queue []interface{} // 定义一个任意类型的切片

func (q *Queue) Push(v interface{}){
  *q = append(*q, v)
  // *q = append(*q, v.(int))
}

func (q *Queue) Pop() interface{}{
  head := (*q)[0]
  *q = (*q)[1:]
  // return head.(int)
  return head
}

func (q *Queue) IsEmpty() bool{
  return len(*q) == 0
}

4、接口的组合

有Retriever、Poster两个接口,然后进行接口的组合,之后可以在session中调用他们。

type Retriever interface {
  Get(url string) string
}

type Poster interface {
  Post(url string,
      form map[string]string) string
}

func download(r Retriever) string{
  return r.Get("pfeiwang.blog.csdn.net")
}

func post(poster Poster){
  poster.Post("pfeiwang.blog.csdn.net",
              map[string]string {
                "name": "Golang",
                "course": "go"
              })
}

// 组合interface
type RetrieverPoster interface{
  Retriever
  Poster
  Connect(host string)// 定义其他方法
}

func Session(s RetrieverPoster){
  // 在传入的Retriever、Poster接口中要同时实现Get和Post
  s.Get()
  s.Post()
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值