文章

golang学习记录(11)

接口–interface

go语言中interface是一种非常重要的类型,是非常重要的组成部分

1、鸭子类型

鸭子类型

当一只鸟走起来像鸭子,游泳起来像鸭子,叫起来也想鸭子,那这只鸟就是鸭子

鸭子类型强调的是事物的方法,而不是内部的结构

也就是说,只要一个对象实现了接口的所有方法,那么这个对象就可以被认为是实现了这个接口,就能将这个对象作为这个接口的实例

2、接口的定义

接口的定义需要用到type和interface关键字,具体的定义格式如下:

1
2
3
4
5
type 接口名 interface{
    方法名1(参数列表) 返回值列表
    方法名2(参数列表) 返回值列表
   ...
}

下面是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
type Duck interface{
    Gaga()
    Walk()
    Swimming()
}

type pskDuck struct{
    legs int
}

func (pd *pskDuck) Gaga(){
    fmt.Println("嘎嘎嘎")
}

func (pd *pskDuck) Walk(){
    fmt.Println("走")
}

func (pd *pskDuck) Swimming(){
    fmt.Println("游泳")
}

func main(){
    var duck Duck = &pskDuck{}
    duck.Gaga()
    duck.Walk()
    duck.Swimming()
}

3、多接口实现

在实际的应用场景中,接口不应该写的太大,一般一个接口只实现一个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
type Duck interface{
    Gaga()
}

type Duck2 interface{
    Walk()
}

type Duck3 interface{
    Swimming()
}

type pskDuck struct{}

func (pd *pskDuck) Gaga(){
    fmt.Println("嘎嘎嘎")
}

func (pd *pskDuck) Walk(){
    fmt.Println("走")
}

func (pd *pskDuck) Swimming(){
    fmt.Println("游泳")
}

func main(){
    var duck Duck = &pskDuck{}
    var duck2 Duck2 = &pskDuck{}
}

在上面的例子中,pskDuck实现了Duck、Duck2、Duck3三个接口,但是在main函数中,只声明了Duck接口,但是却可以将pskDuck的实例赋值给Duck接口,这是因为pskDuck实现了Duck接口的所有方法,所以可以将pskDuck的实例赋值给Duck接口

接口也可以作为结构体的参数

接口的使用非常灵活

代码的解耦

一个类型实现多个接口。一个接口实现多个类型

……

4、接口与动态类型传参

断言

举个例子,做一个加法计算器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
func add(a, b interface{}) interface{}{
    switch a.(type){
    case int:
        ai, _ := a.(int)
        bi, _ := b.(int)
        return ai + bi

    case int32:
        ai, _ := a.(int32)
        bi, _ := b.(int32)
        return ai + bi
    

    case float32:
        ai, _ := a.(float32)
        bi, _ := b.(float32)
        return ai + bi
    
    //……

    default:
        return 0
    }
}


func main(){
    fmt.Println(add(1, 2))
    fmt.Println(add(1, 3))
    fmt.Println(add(1.0, 2.0))
}

5、接口嵌套

接口嵌套达到代码复用的目的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
type MyWriter interface{
    Write(string)
}

type MyReader interface{
    Reader() string
}

type MyReaderWriter interface{
    MyReader
    MyWriter
    ReadWriter()
}

type SreadWriter struct{}

func (srw *SreadWriter) Read(){
    fmt.Println("read")
}

func (srw *SreadWriter) Write(){
    fmt.Println("write")
}

func (srw *SreadWriter) ReadWriter(){
    fmt.Println("readWriter")
}

func main(){
    var mrw MyReaderWriter = &SreadWriter{}
    mrw.Read()

}

6、接口与slice常见的错误

slice不能作为接口的参数,因为slice是一个引用类型,但是接口是一个值类型,所以不能将slice作为接口的参数,但是可以将slice的指针作为接口的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func mPrint(data ... interface{}){
    for _, value := range data{
        fmt.Println(value)
    }
}

func main(){
    //这样是支持的
    var data = []interface{}{
        "aaaaa",
        19,
        1800.00,
    }
    mPrint(data...)
}
本文由作者按照 CC BY 4.0 进行授权