Golang接口使用与理解

Golang接口使用与理解

接口类型是对其他类型行为的概括与抽象。通过使用接口,我们可以写出更加灵活和通用的函数,这些函数不需要绑定在一个特定的实现类型上。Go接口的独特支出在于它是隐式实现的。不需要声明一个类型实现了哪些接口,只要提供接口所必须的方法即可。

定义

1
2
3
4
// 定义一个接口
type Name interface(){
method()
}

接口是一组方法签名,当一个类型为接口中所有的方法提供定义时,它被称为实现该接口。

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
type Shape interface {
peri() float64
area() float64
}

type Triangle struct {
a, b, c float64
}

func (t Triangle) peri() float64{
return t.a + t.b + t.c
}

func (t Triangle) area() float64{
p := t.peri()
return math.Sqrt(p*(p - t.a) * (p - t.b) * (p - t.c))
}

type Circle struct{
radius float64
}

func (c Circle) peri() float64{
return c.radius * 2 * math.Pi
}

func (c Circle) area() float64{
return math.Pow(c.radius, 2) * math.Pi
}

func testShape(s Shape){
fmt.Println("peri:", s.peri(), "area:",s.area())
}

func main() {
t := Triangle{3,3,3}
testShape(t)
c := Circle{2}
testShape(c)
}

在上述代码中,Triangle与Circle实现了Shape的所有接口,那么它们就被视为Shape的鸭子类型,可以直接使用以Shape为参数的函数。

类型判断

通过 instance, ok := 接口对象.(实际类型)判断

1
2
3
4
5
6
7
8
9
func getType(s Shape){
if ins, ok := s.(Triangle); ok{
fmt.Println("is Triangle, edges are", ins.a, ins.b, ins.c )
}else if ins, ok := s.(Circle); ok{
fmt.Println("is Circle, radius is", ins.radius)
}else{
fmt.Println("Unknown")
}
}

通过接口对象.(type)判断

1
2
3
4
5
6
7
8
9
10
func getType2(s Shape){
switch ins := s.(type) {
case Triangle:
fmt.Println("is Triangle, edges are", ins.a, ins.b, ins.c )
case Circle:
fmt.Println("is Circle, radius is", ins.radius)
default:
fmt.Println("Unknown")
}
}

空接口

空接口定义

空接口是特殊形式的接口类型,普通的接口都有方法,而空接口没有定义任何方法。因此,我们可以说所有类型都至少实现了空接口。

1
2
3
type empty_interface interface{

}

空接口使用方法

使用空接口声明实例

interface{}作为类型声明一个实例,那么该实例可以承载任意类型的值。

1
2
3
4
5
6
7
var i interface{}
i = 1
fmt.Println(i)
i = "test"
fmt.Println(i)
i = false
fmt.Println(i)

使用空接口作为函数参数

使用空接口作为函数参数,可以让函数接收任意类型的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func ifTest(iface interface{}){
fmt.Println(iface)
}

func main() {
a := 10
b := "test"
c := false
d := []int{1,2,3}
ifTest(a)
ifTest(b)
ifTest(c)
ifTest(d)
}

// 输出
// 10
// test
// false
// [1 2 3]

使用空接口定义可接受任意类型的容器

1
2
3
4
5
6
7
any := make([]interface{}, 3)
any[0] = 11
any[1] = "helloWolrd"
any[2] = []int{1,2,3,4}
for _, value := range any{
fmt.Println(value)
}

空接口易错点

  1. 空接口可以承载任意值,但不代表任意类型就可以承接空接口类型的值。将空接口类型赋值给固定类型会报错。

  2. 当空接口对象承载数组和切片后该对象不能再进行切片

  3. 当使用空接口来接收其他类型时,其静态类型为interface{},但动态类型并不知晓,因此需要使用类型断言接口对象.(type)获取具体类型