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}

可以明显看出被赋值了

5.指针类型

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

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: 1

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

主函数修改如下:

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)
这样就可以取得具体元素了。
 

6.接口的组合

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方法里面修改了内容导致的。

7.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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章