Go 编程 | 连载 19 - 接口的应用

1,509 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第16天,点击查看活动详情

本文紧接 Go 编程 | 连载 18 - 接口 Interface 的内容

三、接口也支持继承

结构体可以通过组合实现面向对象继承的特性,接口也可以通过组合实现继承。

定义 Mark1、Mark2 和 Mark44 三个接口,Mark44 除了拥有 Mark1 和 Mark2 的所有功能(方法)外,还有自己独特的功能。

type Mark1 interface {
   Flames() // 喷火
}

type Mark2 interface {
   Fly() // 飞行
}

type Mark44 interface {
   Mark1
   Mark2
   AntiHulk()
}

type IronMan struct {
   Address string
}

func (i IronMan) Flames(){
   fmt.Println("喷火ing")
}

func (i IronMan) Fly(){
   fmt.Println("飞行ing")
}

func (i IronMan) AntiHulk(){
   fmt.Println("反浩克ing")
}

在 main 方法中声明一个 Mark44 接口类型的变量并赋值一个 IronMan 结构体的实例化对象。

func main(){

   var mark44 Mark44 = IronMan{"Earth 616"}

   mark44.Fly()
   mark44.AntiHulk()
}

执行上述代码,输出结果如下:

飞行ing
反浩克ing

当然组合结构体实现组合接口也是可行的,在上述代码中增加一个结构体 Mankind,并将该结构体放进 IronMan 结构体中

type Mankind struct {
   Name string
}

type IronMan struct {
   Mankind
   Address string
}

修改 main 方法

func main(){

   man := Mankind{"tony"}

   var mark44 Mark44 = IronMan{man, "Earth 616"}

   mark44.Fly()
   mark44.AntiHulk()
}

再次调用 main 方法,输出结果如下:

飞行ing
反浩克ing

四、空接口的应用场景

Go 中允许接口中不包含任何方法,既允许空接口的存在,空接口可以直接定义;

type 接口名 interface {
}

也可以通过变量声明一个空接口

var 变量名 interface{}

空接口变量可以被赋值任何类型的数据。

空接口作为 Map 的值

在定义 Map 的时候通常都需要指定 Map 的键和值的类型,也就是说 Map 中值的类型是固定的,但是如果使用空接口作为值的类型的话,则值可以为任意类型。

func main(){

   info := make(map[string]interface{})

   info["name"] = "stark"
   info["age"] = 33
   info["suit"] = []string{"Mark2", "Mark3", "Mark44", "Mark57"}
   info["balance"] = 3.14

   fmt.Println(info)

}

执行上述代码,输出结果如下:

map[age:33 balance:3.14 name:stark suit:[Mark2 Mark3 Mark44 Mark57]]

空接口作为函数参数

前面提到空接口类型变量可以接收任意类型的数据,那么将空接口作为函数的参数之后,函数的参数也将不受类型的限制。

新增一个 output 函数,以空接口作为参数

func output(i interface{}){
   fmt.Printf("%v\n", i)
}

在 main 函数中新增如下代码

func main(){
   
   // 原代码保持不变
   output(info)
   output(info["suit"])
   output(info["name"])

}

执行上述代码,输出结果如下:

map[age:33 balance:3.14 name:stark suit:[Mark2 Mark3 Mark44 Mark57]]
[Mark2 Mark3 Mark44 Mark57]
stark

五、Go 的 error 接口

Go 中的 error 类型也是一个接口,该接口包含了一个 Error() 方法,返回一个 string 字符串

image.png

可以使用结构体来实现 error 接口,用作自定义的业务错误类型

func main() {

   var err error = LoginError{"用户名或密码错误", 00001}

   if err != nil {
      fmt.Println(err)
   } else {
      fmt.Println("登录成功")
   }

}

type LoginError struct {
   Message string
   Code int
}

func (err LoginError) Error() string{
   return err.Message
}

执行上述代码,输出结果如下:

用户名或密码错误

除了实现 error 接口外还可以导入 errors 标准库,通过 errors.New("错误信息") 实例化的方式来给 err 接口变量赋值

import (
   // 导入 errors 包 
   "errors"
   "fmt"
)

func main() {

   var err error = errors.New("用户名密码错误")
    
   // 其余代码保持不变 
}

但是最常用的其实是第三种方式,既通过 fmt 包下的 Errorf 函数的返回来给 error 接口变量赋值。

Errorf 函数的返回值是一个 error 接口类型

image.png

也可以通过这种方式给 error 接口变量赋值

var err error = fmt.Errorf("%v", "用户名或者密码错误")