关于 go 语言接口的简单介绍

接口对于 go 实现面向对象来说非常重要,如果没有它 go 的结构体(struct)也就只能存储一些信息, 但是相关的方法将会变得非常麻烦

什么是接口?

接口就是制定一个通用的规范,只要符合这个规范就能使用这个借口(听起来像是车轱辘话)

接口类型

比如我定义了一个接口

1
2
3
4
type example interface{
  a()
  b()
}

他定义了两个方法,只要有结构体中含有 a(),b()两个方法就能实现这个接口,通过接口来统一调用, 如下

 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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//package main
//import "fmt"

//定义一个基本的类
type Human struct{
  name  string
  age   int
  phone string
}

type Student struct{
  Human //继承 human 中的字段
  school string
  loan   float32
}

type Employee struct{
  Human
  company string
  money   float32
}

//Human 实现 Sayhi 方法
func (h Human) Sayhi(){
  fmt.Printf("hi my name is %s and my phone is %s \n", h.name,h.phone)
}

//Human 实现 Sing 方法
func (h Human) Sing(lyrics string)  {
  fmt.Println("galigaygay galigaygay ...",lyrics)
}

//student 复写 Sayhi 方法
func (sdt Student) Sayhi()  {
  fmt.Printf("my name is %s and my school is %s \n", sdt.name,sdt.school)
}

//定义一个通用的接口
type Men interface{
  Sayhi()
  Sing(lyrics string)
}

func main () {
  //实例化两种类
  mike := Student{Human{"mike",25,"18333636999"},"MIT",3.14}
  jack := Employee{Human{"jack",30,"18333636998"},"hotcast",20000}

  //定义一个接口变量
  var i Men

  //接口实现了 Student 类的方法
  fmt.Println("下面有请 mike 开始他的表演:")
  i = mike
  i.Sayhi();
  i.Sing("dongci daci")


  //接口实现了 Employee 类的方法
  fmt.Println("下面有请 mike 开始他的表演:")
  i = jack
  i.Sayhi();
  i.Sing("haha haha haha")
}

这里的 Men 接口被所有继承了Human的结构体的方法所实现,所以这些实例化的结构体可以赋值给 Men的接口变量上,我们在 go 语言中的面向对象开发可以说就是面向接口在开发,由接口来组成一个个的 变量, 这和 php 的接口有所不同,在 php 中,接口是需要被 class 来继承,然后class 中去实现 interface 中 指定的方法,比如

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
interface Human{
  function sayHi();
  function sing();
}

class Student implements Human{
  public function sayHi(){
    // TODO:
  }
  public function sing(){
    // TODO:
  }
}

这样子的, 每个类需要指定继承哪些接口才可以去实现接口,而 go 和 php 正好相反,是谁实现了我的规范 谁就可以用我的接口,实现顺序正好倒过来了

再举一个接口的例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
	"fmt"
	"strconv"
)

type Human struct {
	name  string
	age   int
	phone string
}

// 这里需要把 int 类型转换成字符串,否则使用 + 来连接字符的时候报数据类型不匹配的错误
func (h Human) String() string {
	return "<" + h.name + "-" + strconv.Itoa(h.age) + "years old ,phone is " + h.phone + "/>"
}

func main() {
	Duck := Human{"duck", 22, "110-120-119"}
	fmt.Println("this human is :", Duck)
}

上述例子当中我们实现了 fmt.Println 中的一个接口

1
2
3
4
5
type Stringer interface {
  String() string
}

这样之后,调用 `Human`  String() 函数就能被 `fmt.Println()` 所用了