Golang | 既是接口又是类型,interface是什么神仙用法?

2020-07-24 00:00:00 是一个 方法 接收 类型 指针

今天是golang专题的第12篇文章,我们来继续聊聊interface的使用。

在上一篇文章当中我们介绍了面向对象的一些基本概念,以及golang当中interface和多态的实现方法。今天我们继续来介绍interface当中其他的一些方法。


类型interface

在Java以及其他语言当中接口是一种写法规范,而在golang当中,interface其实也是一种值,它可以像是值一样传递。并且在它的底层,它其实是一个值和类型的元组。

这里我们来看下golang官方文档当中的一个例子:

package main

import (
 "fmt"
 "math"
)

type I interface {
 M()
}

type T struct {
 S string
}

func (t *T) M() {
 fmt.Println(t.S)
}

type F float64

func (f F) M() {
 fmt.Println(f)
}

func main() {
 var i I

 i = &T{"Hello"}
 describe(i)
 i.M()

 i = F(math.Pi)
 describe(i)
 i.M()
}

func describe(i I) {
 fmt.Printf("(%v, %T)\n", i, i)
}

在上面的代码当中定义了一个叫做describe的方法,在这个方法当中我们输出了两个值,一个是接口i对应的值,另一个是接口i的类型

我们输出的结果如下:


可以看到接口当中既存储了对应的结构体的实例的信息,也存储了结构体的类型。因此interface可以理解成一种特殊的类型。

实际上也的确如此,我们可以把interface理解成一种数据类型,它可以接收任何类型的值。我们看下下面这种用法:

var a1 interface{} = 1
var a2 interface{} = "abc"
list := make([]interface{}, )
list = append(list, a1)
list = append(list, a2)
fmt.Println(list)

在代码当中我们创建了一个interface{}类型的slice,它可以接收任何类型的值和实例。另外我们用interface{}这个类型也可以接收任何结构体的值。这里可能会有些迷惑,其实很容易想明白。interface表示一种类型,可以接收任何实现了interface当中规定的方法的类型的值。当我们定义inteface{}的时候,其实是定义了空的interface,相当于不需要实现任何方法的空interface,所以任何类型都可以接收,这也就是它成为类型的原因。

我们接收当然没有问题,问题是我们怎么使用这些interface类型的值呢?

一种方法是我们可以判断一个interface的变量类型。判断的方法非常简单,我们在interface的变量后面用.(type)的方法来判断。它和map的key值判断一样,会返回一个值和bool类型的标记。我们可以通过这个标记判断这个类型是否正确。

if v, ok := a1.(int); ok {
    fmt.Println(v)
}

如果类型比较多的话使用switch也是可以的:

switch v := i.(type) {
case int:
    fmt.Println("int")
case string:
    fmt.Println("string")
}

相关文章