GO语言笔记--接口

1.接口interface

1)接口是一个或多个方法签名的集合

2)只要某个类型拥有该接口的所有方法签名,即算实现该接口无需显示声明实现了哪个接口,这称为Structural Typing

3)接口只有方法声明,没有实现,没有数据字段

4)接口可以匿名嵌入其他接口,或嵌入到结构中

5)将对象赋值给接口时,会发生拷贝,而接口内部存储的是指向这个复制品的指针,既无法修改复制品的状态,也无法获取指针

6)只有当接口存储的类型和对象为nil时,接口才等于nil

7)接口调用不会做receiver的自动转换

8)接口统一支持匿名自动方法

9)接口也可以实现类似OOP中的多态

10)空接口可以作为任何类型数据的容器

11)接口是由使用者定义得

 

2.类型断言

1)通过类型断言的ok pattern可以判断接口中的数据类型

2)使用tupe switch 则可针对空接口进行比较全面的类型判断

 

3.接口转换

可以将拥有超集的接口转换为子集的接口

 

实例,使用者定义接口

创建一个retiever目录,里面包含main.go 以及csdn/csdnRetiever.go两个文件

main.go代码,这里面使用到了定义的csdn这个包调用接口Retiever的Get方法:

package main

import (
    "fmt"
    "my-code/test-code/retiever/csdn"
)

type Retiever interface {
    Get(url string) string
}

func download(r Retiever) string {
    return r.Get("www.csdn.com")
}

func main() {
    var r Retiever
    r = csdn.Retiever{"hello www.csdn.com"}
    fmt.Println(download(r))
}

csdn/csdnRetiever.go代码中包含接口定义:

package csdn

type Retiever struct {
    Contents string
}

func (r Retiever) Get(url string) string {
    return r.Contents
}


上述代码传入一个url字符串并直接return

输出:
API server listening at: 127.0.0.1:34276
hello www.csdn.com

实例,访问百度

创建一个retiever目录,里面包含main.go 以及baidu/baidu.go两个文件

main.go代码,这里面使用到了定义的baidu这个包调用接口Retiever的Get方法:

package main


import (
    "fmt"
    "my-code/test-code/retiever/baidu"
)

type Retiever interface {
    Get(url string) string
}

func download(r Retiever) string {
    return r.Get("http://www.baidu.com")
}

func main() {
    var r Retiever
    r = baidu.Retiever{}
    fmt.Println(download(r))
}


baidu/baidu.go代码直接调用内置http接口访问百度:

package baidu

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

type Retiever struct {
    UserAgent string
    TimeOut time.Duration
}

func (r Retiever) Get(url string) string {
    resp, err := http.Get(url)
    if err != nil {
        panic(err)
    }
    result, err := httputil.DumpResponse(resp, true)
    resp.Body.Close()
    if err != nil {
        panic(err)
    }
    return string(result)
}

上述实例运行结果是获取到了百度首页的html源码

 

4.查看接口内部元素

接口内部究竟是什么内容呢,将上述main.go代码修改如下打印出来查看:

func main() {
    var r Retiever
    r = baidu.Retiever{}
    //fmt.Println(download(r))
    fmt.Printf("%T\n%v\n", r, r)
}

运行结果如下:
API server listening at: 127.0.0.1:18265
baidu.Retiever
{ 0s}

上述打印看出%T打印的内容是baidu.Retiever这是接口名称,%v的内容是{ 0s},这是因为里面两个元素UserAgent未赋值因此是个空格,TimeOut未赋值所以默认0秒。为了更清晰的看出效果,下面将上述元素赋值查看:

package main

import (
    "fmt"
    "my-code/retiever/baidu"
    "time"
)

type Retiever interface {
    Get(url string) string
}

func download(r Retiever) string {
    return r.Get("http://www.baidu.com")
}

func main() {
    var r Retiever
    r = baidu.Retiever{
        UserAgent: "Mozilla/5.0",
        TimeOut: time.Minute,
    }
    //fmt.Println(download(r))
    fmt.Printf("%T\n%v\n", r, r)
}

运行效果如下:
API server listening at: 127.0.0.1:16843
baidu.Retiever
{Mozilla/5.0 1m0s}

可以明显看出被赋值了

 

指针类型

如果接口类型修改为指针类型呢,代码如下:

baidu/baidu.go
package baidu

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

type Retiever struct {
    UserAgent string
    TimeOut time.Duration
}

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

    result, err := httputil.DumpResponse(resp, true)
    resp.Body.Close()
    if err != nil {
        panic(err)
    }
    return string(result)
}


main.go源码不变:

package main

import (
    "fmt"
    "my-code/retiever/baidu"
    "time"
)

type Retiever interface {
    Get(url string) string
}

func download(r Retiever) string {
    return r.Get("http://www.baidu.com")
}

func main() {
    var r Retiever
    r = baidu.Retiever{
        UserAgent: "Mozilla/5.0",
        TimeOut: time.Minute,
    }

    //fmt.Println(download(r))
    fmt.Printf("%T\n%v\n", r, r)
}


那么上述就会出错,执行报错如下:

# my-code/retiever
.\main.go:19:4: cannot use baidu.Retiever literal (type baidu.Retiever) as type Retiever in assignment:
baidu.Retiever does not implement Retiever (Get method has pointer receiver)
exit status 2
Process exiting with code: 

此时就要修改为取地址了:

主函数修改如下:

func main() {
    var r Retiever
    r = &baidu.Retiever{
        UserAgent: "Mozilla/5.0",
        TimeOut: time.Minute,
    }
    //fmt.Println(download(r))
    fmt.Printf("%T\n%v\n", r, r)
}

这样执行就不会出错了。

Type assertion

通过指针类型获取内部元素:

val := r.(*baidu.Retiever)
fmt.Println(val.TimeOut)

这样就可以取得具体元素了。

 

5.接口的组合

baidu/baidu.go提供Retiever接口:

package baidu

type Retiever struct {
    Contents string
}

func (r *Retiever) Post(url string, form map[string]string) string {
    r.Contents = form["contents"]
    return "ok"
}

func (r *Retiever) Get(url string) string {
    return r.Contents
}


main.go代码这里面使用Poster和Retiever两个接口组合成一个RetieverPoster接口

package main

import (
    "fmt"
    "my-code/retiever/baidu"
)

type Retiever interface {
    Get(url string) string
}

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

const url = "http://www.baidu.com"

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

func post(poster Poster) {
    poster.Post(url,
        map[string]string{
            "name": "baidu",
            "course": "golang",
        })
}

type RetieverPoster interface {
    Retiever
    Poster
}

func session(s RetieverPoster) string {
    s.Post(url, map[string]string{
        "contents": "hello baidu",
    })
    return s.Get(url)
}

func main() {
    retriever := baidu.Retiever{"hello http://www.baidu.com"}
    fmt.Println(session(&retriever))
}

执行效果如下:
API server listening at: 127.0.0.1:41871
hello baidu

虽然传入的是"hello http://www.baidu.com"但是输出的却是"hello baidu"这是因为在session方法里面修改了内容导致的。

 

6.GO语言常用系统接口

Stringer接口,在fmt/print.go内:

type Stringer interface {
    String() string
}

应用:在baidu包内实现一个String(),代码如下:

baidu/baidu.go

package baidu

import "fmt"

type Retiever struct {
    Contents string
}

func (r *Retiever) String() string {
    return fmt.Sprintf(
        "Retriver:{Contents=%s}", r.Contents)
}

func (r *Retiever) Post(url string, form map[string]string) string {
    r.Contents = form["contents"]
    return "ok"
}

func (r *Retiever) Get(url string) string {
    return r.Contents
}


main.go

package main

import (
    "fmt"
    "my-code/retiever/baidu"
)

type Retiever interface {
    Get(url string) string
}

func main() {
    r := &baidu.Retiever{
        Contents: "hello word",
    }
    fmt.Printf("%T\n%v\n", r, r)
}

输出:
API server listening at: 127.0.0.1:39863
*baidu.Retiever
Retriver:{Contents=hello word}

此外还有两个接口在io.go包内,分别是Reader和Writer

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

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

实例:

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "strings"
)

func printFile(name string) {
    file, err := os.Open(name)
    if err != nil {
        panic(err)
    }
    testIoReader(file)
}

func testIoReader(reader io.Reader) {
    scanner := bufio.NewScanner(reader)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }
}


func main() {
    printFile("ioTest.go")
    fmt.Println("##############print string#################")
    s := `abc"d"
    beijing
    nihao
    hello`
    testIoReader(strings.NewReader(s))
}

可以打印文件内容或者字符串里面的内容。

小结:

1.接口变量里面有什么

1)接口变量自带指针

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

3)指针接收者实现只能以指针方式使用;值接受者都可

2.查看接口变量

1)表示任何类型:interface{}

2)Type Assertion

3)Type Switch

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值