Go面向接口篇

接口

Go语言是面向接口的,面向对象只支持封装,其余继承多态靠接口来实现的。

接口定义:使用者download------->实现者retriever  

注意:接口由使用者定义(传统面向对象中:file实现文件的人告诉他人他实现了可读可写这两个接口)

接口的实现:是隐式的

接口变量:包括:实现者的类型、实现者的值    接口变量里面到底是值还是指针,可以选择。

接口变量自带指针:使用时候接口变量注意不要用&地址

接口变量同样采用值传递,几乎不需要使用接口的指针

指针接收者只能一指针方式使用,值接收者两者都可。

查看接口变量

Type Assertion

Type Switch

表示任何类型:interface{}  

例子:比如queue中目前只能支持int类型

//只支持int类型  注意这里举例只列出了Push实际操作记得将Pop也修改

type Queue []int

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

//支持任何类型

type Queue []interface{}

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

例子:1)如果只想支持int类型  2)例子:假如接口肚子都没限定类型,如何限定int

duck typing 

并不是Go语言特有的

1)大黄鸭是鸭子吗?

传统类型系统:脊索动物门、脊椎动物亚门等  按此理来说不是鸭子(没有生命)

duck typing:像鸭子走路,长得像 等就是鸭子  (描述事务的外部行为而非内部结构)

总结:应该从实物角度而言,是不是鸭子。

2)go属于结构化类型系统,类似duck typing(需要动态绑定)。这里假设Go结构duck typing

3)其他语言中的duck typing

Python中的:
def download(retriever):
return retriever.get("www.baidu.com") 注意:运行时候才知道传入的retriever有没有get
通常需要注释来说明接口

C++中的:本身就支持type typing 通过模板来支持
template <class R>
string download(const R& retriever) {
return retriever.get("www.baidu.com")
注意:编译时才知道传入的retriever有没有get
需要注释来说明接口(因为敲代码时候不知道)

Java中没有duck typing 类似代码是:
<R extends Retriever>
String download(R r){
return r.get("www.baidu.com");
}
注意:传入的参数必须实现Retriever接口 与Python与C++相比不需要注释说明
不是duck typing
问题:多个需求必须让R实现多个接口,这就有问题了
4)go语言中的:
同时需要Readable、Appendable怎么办?(Java的办法:apache polygene 思路就是把两个接口组装起来,非常难用)
同时具有Python、C++ 的duck typing灵活性(不需要注释),以及Java的类型检查

目录结构以及代码

main.go

package main

import (
    "fmt"

    "time"

    "learngo/retriever/mock"
    "learngo/retriever/real"
)
//方法改名只影响到使用者
type Retriever interface {
    Get(url string) string   //不需要加func
}

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

const url = "http://www.imooc.com"  //如果不加http://会报错
//使用者
func download(r Retriever) string {
    return r.Get(url)
}

func post(poster Poster) {
    poster.Post(url,
        map[string]string{
            "name":   "ccmouse",
            "course": "golang",
        })
}
//组合接口
type RetrieverPoster interface {
    Retriever
    Poster
}
func session(s RetrieverPoster) string {
    s.Post(url, map[string]string{
        "contents": "another faked imooc.com",
    })
    return s.Get(url)
}

func main() {
    var r Retriever  //必须要去实现  mockretriever
//r 肚子里究竟是什么?  一个类型,一个值(指针,或者拷贝的真实值)
    mockRetriever := mock.Retriever{
        Contents: "this is a fake imooc.com"}
    r = &mockRetriever   //值接收者可以去掉&,但是也可以加上
    inspect(r)
//真实的Retriver   指针接收者必须要&地址
    r = &real.Retriever{
        UserAgent: "Mozilla/5.0",
        TimeOut:   time.Minute,
    }
//方法1 inspect(r) //方法2
// Type assertion 通过r.(*内容)来获得 可能会出错,为了防止出错加ok if mockRetriever, ok := r.(*mock.Retriever); ok { fmt.Println(mockRetriever.Contents) } else { fmt.Println("r is not a mock retriever") } fmt.Println( "Try a session with mockRetriever") fmt.Println(session(&mockRetriever)) //这里如果改为&retriever也可以 } //看看r肚子里面是什么东西 func inspect(r Retriever) { fmt.Println("Inspecting", r) fmt.Printf(" > Type:%T Value:%v\n", r, r) fmt.Print(" > Type switch: ") switch v := r.(type) { case *mock.Retriever: fmt.Println("Contents:", v.Contents) case *real.Retriever: fmt.Println("UserAgent:", v.UserAgent) } fmt.Println() }

mockretriever.go

package mock

import "fmt"
//名字最好不要用mockRetriever这样会重复
type Retriever struct {
    Contents string
}
//常用系统接口 相当于其他语言的toString
func (r *Retriever) String() string {
    return fmt.Sprintf(
        "Retriever: {Contents=%s}", r.Contents)
}
//实现者还想实现Post方法  指针接收者
func (r *Retriever) Post(url string,
    form map[string]string) string {
    r.Contents = form["contents"]
    return "ok"
}
//语言本身不需要说明 只需要实现Get方法即可
func (r *Retriever) Get(url string) string {
    return r.Contents
}

retriever.go

package real

import (
    "net/http"
    "net/http/httputil"
    "time"
)
//真实的Retriever
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)
    }

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

    resp.Body.Close()  //读完了之后要去close它

    if err != nil {
        panic(err)
    }

    return string(result)
}

输出

Inspecting Retriever: {Contents=this is a fake imooc.com}
 > Type:*mock.Retriever Value:Retriever: {Contents=this is a fake imooc.com}
 > Type switch: Contents: this is a fake imooc.com

Inspecting &{Mozilla/5.0 1m0s}
 > Type:*real.Retriever Value:&{Mozilla/5.0 1m0s}
 > Type switch: UserAgent: Mozilla/5.0

r is not a mock retriever
Try a session with mockRetriever
another faked imooc.com

Process finished with exit code 0

 常用系统接口

Stringer 相当于其他语言的toString
type Stringer interface {
      String() string
}

Reader 接口 Writer接口 :对文件的抽象 其实不一定是文件可以是其他的

type Reader interface {
      Read(p []byte) (n int , err error)
}
type Writer interface {
      Write(p []byte) (n int , err error)
}
 

 接口的组合:

type ReadWriter interface {
      Reader
      Writer
}

猜你喜欢

转载自www.cnblogs.com/ycx95/p/9361952.html
今日推荐