Go 编程 | 连载 19 - 接口的应用
本文紧接 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 字符串
可以使用结构体来实现 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 接口类型
也可以通过这种方式给 error 接口变量赋值
var err error = fmt.Errorf("%v", "用户名或者密码错误")
转载自:https://juejin.cn/post/7132497202265456653