接口(interface)定义了一个对象的行为规范,之定义规范不实现。

接口类型

Go语言中接口(interface)是一种类型,一种抽象的类型。

interface是一组method的集合,是duck-type programming的一种体现。接口做的事情就像是定一个协议(规则)。不关心属性(数据),只关心行为方法。

接口的定义

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

其中:

  • 接口名:使用type将接口定义为自定义类型名时。Go语言在接口命名时,一般会在单词后面加er,如有写操作的接口叫做Writer,有字符串功能的接口叫做stringer。接口名最好能突出该接口类型的含义。

  • 方法名:当方法名首字母是大写并且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码当问。

  • 参数列表、返回值列表:参数列表和返回值列表中的参数变量名可以省略。

    1
    2
    3
    type writer interface{
    Writer([]byte) error
    }

    接口实现的条件

    一个对象只要实现了接口中的所有方法,那么就实现了这个接口。

    1
    2
    3
    4
    5
    //定义接口
    type speaker interface {
    //接口方法
    speak()
    }
    1
    2
    3
    4
    5
    type cat struct{}

    func (c cat) speak(){
    fmt.Println("喵喵喵~")
    }
    1
    2
    3
    4
    5
    type person struct{}

    func (p person) speak(){
    fmt.Println("啊啊啊~")
    }

    接口类型变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var speaker speaker

    var d dog
    var c cat
    var p person

    speaker = d
    speaker.speak()
    speaker = c
    speaker.speak()
    speaker = p
    speaker.speak()

值接收者和指针接收者实现接口的区别

  • 值接收者实现接口

    因为Go语言中有使用指针类型变量求值的语法糖。

    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
    34
    //值接收者
    type animal interface{
    move()
    eat(string)
    }

    type cat struct{
    name string
    feet int64
    }

    //实现接口
    func (c cat) move(){
    fmt.Println("走猫步~~")
    }

    func (c cat) eat(food string){
    fmt.Printf("猫吃%s!", food)
    }

    func main() {
    //定义接口变量
    var a1 animal
    //值类型
    c1 := cat{"Tom", 4}
    //指针类型
    c2 := &cat{"小花", 4}
    //接收值类型
    a1 = c1
    fmt.Println(a1)
    //接收指针类型
    a1 = c2
    fmt.Println(a1)
    }
  • 指针接收者

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    type car interface {
    run()
    }

    type qqCar struct{
    name string
    }

    func (q *qqCar)run(){
    fmt.Println("奇瑞QQ")
    }

    func main() {
    //定义接口变量
    var ca car
    //指针接收者只能接收指针类型
    ca1 := &qqCar{"奇瑞QQ"}
    ca = ca1
    fmt.Println(ca)
    }

类型与接口的关系

一个类型可以实现多个接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type eater interface {
eat(string)
}

type mover interface {
move()
}

func main() {
var e eater
var m mover

c := cat{"Tom", 4}

a.eat("饼干")
e = c
e.eat("鱼")
m = c
m.move()
}

多个类型实现一个接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type dog struct{}

func (d dog) speak(){
fmt.Println("汪汪汪~")
}

type cat struct{}

func (c cat) speak(){
fmt.Println("喵喵喵~")
}

type person struct{}

func (p person) speak(){
fmt.Println("啊啊啊~")
}

//定义接口
type speaker interface {
//接口方法
speak()
}

一个接口的方法,不一定需要一个类型完全实现,接口的方法可以通过在类型中嵌入其他类型或者结构体来实现。

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
type animal interface {
eat(string)
move()
}

type cat struct {
name string
smallCat
}

func (c cat) move() {
fmt.Println("大猫移动")
}

type smallCat struct{
age int64
}

//接口eat(string) 方法由小猫来实现
func (s smallCat) eat(food string){
fmt.Printf("小猫吃%s", food)
}

func main() {
//定义接口变量
var a animal

c := cat{name: "大猫", smallCat: smallCat{23},}
a = c
fmt.Println(a)
}

接口嵌套

接口与接口之间可以进行嵌套创造出新接口

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
34
35
36
37
38
39
40
41
42
43
44
45
//接口可以嵌套接口
type animal interface {
eater
mover
}

type eater interface {
eat(string)
}

type mover interface {
move()
}

//一个结构体可以实现多个接口
type cat struct {
name string
feet int64
}

func (c cat) eat(food string){
fmt.Printf("猫吃%s", food)
}

func (c cat) move(){
fmt.Println("走猫步~")
}

func main() {
var a animal

var e eater

var m mover

c := cat{"Tom", 4}

a = c
a.move()
a.eat("饼干")
e = c
e.eat("鱼")
m = c
m.move()
}

空接口

空接口是指没有定义任何方法的接口。任何类型都实现了空接口。

空接口类型的变量可以储存任意类型的变量。

空接口用作方法的参数

1
2
3
4
//空接口用作方法的参数
func show(a interface{}){
fmt.Printf("type:%T, value:%v\n", a, a)
}

空接口作为map的值

1
2
3
4
5
6
var maps map[string]interface{}
maps = make(map[string]interface{}, 16)
maps["name"] = "张三"
maps["age"] = 18
maps["merrier"] = true
maps["hobby"] = [...]string{"唱", "跳", "rap"}

类型断言

空接口可以储存任意类型的值,使用类型断言获取其具体的值

1
2
3
4
//value:该接口类型的值,T 是否为T(string)类型
value, ok := x.(T)
//x: 表示类型为interface{}的变量
//T: 表示断言x可能是的类型

要断言多次可以使用switch进行断言

1
2
3
4
5
6
7
8
9
10
11
12
func assign2(a interface{}){
switch a.(type) {
case string:
fmt.Println("是一个字符串")
case int:
fmt.Println("是一个字符串")
case bool:
fmt.Println("是一个字符串")
case int64:
fmt.Println("是一个字符串")
}
}