Go 编程 | 连载 18 - 接口 Interface

简介: Go 编程 | 连载 18 - 接口 Interface

一、Go 语言中的接口

很多编程语言中都有接口的概念,静态语言 Java 中的接口和 Go 中的接口地位或者概念是不一样的,Go 语言中的接口与 Python 中的接口比较像。

Go 中的接口是一种协议,既调用方和实现方均需要遵守的一种协议,按照统一的方法命名参数类型和数量来协调逻辑处理的过程。

接口的声明

接口是一种协议,一种规范;定义接口时只需定义规范无须关心实现的细节。

type 接口名 interface {
    方法1 (参数列表) 返回值列表
    方法2 (参数列表) 返回值列表
    ...
}
复制代码

在 Go 语言中 interface 名字仍然以单个词为优先。命名基本采用驼峰命名法,首字母根据访问控制大写或者小写。对于拥有唯一方法或通过多个拥有唯一方法的接口组合而成的接口,Go 语言的惯例是一般用"方法名+er"的方式为 interface 命名,例如 Reader、Writer 等。

Go 是区分大小写的,当方法名首字母和接口名首字母都是大些时,这个方法可以被接口所在的包之外的代码访问。

接口方法中参数列表和返回值列表中的变量名可以忽略。

func main() {
   thor := Hero{"Thor, God of Thunder"}
   thor.Hammer()
   thor.Aex()
}
type Fighter interface {
   Hammer() string
   Aex() string
}
type Hero struct {
   Name string
}
func (hero Hero) Hammer() string {
   fmt.Printf("%v 正在使用喵喵锤\n", hero.Name)
   return "Hammer"
}
func (hero Hero) Aex() string {
   fmt.Printf("%v 正在使用暴风战斧\n", hero.Name)
   return "Aex"
}
复制代码

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

Thor, God of Thunder 正在使用喵喵锤
Thor, God of Thunder 正在使用暴风战斧
复制代码

结构体实现一个接口就需要实现接口中的所有方法,实现方法需要保持方法签名一致,包括方法名称、参数列表、返回值列表,只要有一个不一致都不能算是实现这个接口,并且在调用时会导致报错。

比如方法名不一致会报错:

# command-line-arguments
./ex9.go:9:7: thor.Aex undefined (type Hero has no field or method Aex)
复制代码

Go 语言中的接口也是一种类型,可以直接声明一个接口类型的变量

var fighter Fighter
复制代码

一个小陷阱

在实现接口方法时,方法的接收者如果是结构体指针,那么在给接口变量赋值时就只能赋值结构体指针类型,如果还是赋值结构体实例化对象怎会报错。

type Course struct {
   Name string
   Price float64
}
type Outputer interface {
   Output() string
}
// 使用结构体指针作为函数接收者
func (c *Course) Output() string {
   fmt.Println(c.Name)
   return ""
}
复制代码

结构体实现接口方法时函数接收者使用指针形式,在将实例化结构体赋值给接口变量时会报错,如下图所示:

image.png

二、接口是一种抽象类型

Go 中多态的实现

保持 Hero 结构体不变,在增加一个 Evil 结构体也实现 Fighter 接口的两个方法

type Evil struct {
   Name string
}
func (evil Evil) Hammer() string {
   fmt.Printf("%v 正在使用喵喵锤\n", evil.Name)
   return "Evil - Hammer"
}
func (evil Evil) Aex() string {
   fmt.Printf("%v 正在使用暴风战斧\n", evil.Name)
   return "Evil - Aex"
}
复制代码

在 main 方法中声明一个 Fighter 接口变量,并赋值一个 Hero 结构体实例

func main() {
   // 多态
   var f Fighter = Hero{"Thor, God of Thunder"}
   f.Aex()
   f.Hammer()
}
复制代码

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

Thor, God of Thunder 正在使用暴风战斧
Thor, God of Thunder 正在使用喵喵锤
复制代码

上述代码中将结构体实例赋值给一个接口类型变量,实现基于接口的调用,而不是实例化对象本身的调用,如果接口类型变量赋的值不是 Hero 结构体的实例化对象,而是 Evil 结构体的实例化对象,只需更改赋值即可实现 Evil 结构体对 Fighter 接口方法的调用。

func main() {
   // 多态
   var f Fighter = Evil{"Thanos"}
   f.Aex()
   f.Hammer()
   fmt.Printf("%T", f)
}
复制代码

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

Thanos 正在使用暴风战斧
Thanos 正在使用喵喵锤
main.Evil
复制代码

接口实际的类型就是赋值的结构体类型。

接口作为函数参数

接口也可以作为函数的参数,比如我们定义两个方法 HeroSwingStormbreaker 和 EvilSwingStormbreaker,不管是 Hero 还 Evil 都可以拿起暴风战斧,两个函数实现的功能完全是一致的,这种方式就会导致代码的冗余。

func HeroSwingStormbreaker(hero Hero) {
   fmt.Printf("%v is swing Stormbreaker", hero)
}
func EvilSwingStormbreaker(evil Evil) {
   fmt.Printf("%v is swing Stormbreaker", evil)
}
复制代码

如果只定义一个方法,并且将 Fighter 接口作为参数,在 Hero 和 Evil 都实现 Fighter 接口的前提下,Hero 和 Evil 都实现拿起暴风战斧的功能。

func main() {
   SwingStormbreaker(f)
}
func SwingStormbreaker(f Fighter) {
   fmt.Printf("%v is swing Stormbreaker", f)
}
复制代码

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

{Thanos} is swing Stormbreaker


相关文章
|
6天前
|
设计模式 存储 监控
《Go 简易速速上手小册》第4章:接口与抽象(2024 最新版)(上)
《Go 简易速速上手小册》第4章:接口与抽象(2024 最新版)
46 1
|
6天前
|
程序员 Go
|
6天前
|
存储 安全 Go
掌握Go语言:Go语言类型转换,无缝处理数据类型、接口和自定义类型的转换细节解析(29)
掌握Go语言:Go语言类型转换,无缝处理数据类型、接口和自定义类型的转换细节解析(29)
|
6天前
|
数据库连接 Go 数据库
【Go 语言专栏】Go 语言中的错误注入与防御编程
【4月更文挑战第30天】本文探讨了Go语言中的错误注入和防御编程。错误注入是故意引入错误以测试系统异常情况下的稳定性和容错性,包括模拟网络故障、数据库错误和手动触发错误。防御编程则强调编写代码时考虑并预防错误,确保程序面对异常时稳定运行。Go语言的错误处理机制包括多返回值和自定义错误类型。结合错误注入和防御编程,可以提升软件质量和可靠性,打造更健壮的系统。开发人员应重视这两方面,以实现更优质的软件产品。
|
6天前
|
网络协议 安全 Go
【Go语言专栏】Go语言中的WebSocket编程
【4月更文挑战第30天】本文介绍了在Go语言中使用WebSocket进行实时Web应用开发的方法。通过第三方包`gorilla/websocket`,开发者可建立WebSocket服务器和客户端。文中展示了如何创建服务器,升级HTTP连接,以及处理读写消息的示例代码。同时,客户端的创建和通信过程也得以阐述。文章还提及WebSocket的生命周期管理、性能与安全性考虑,以及实践中的最佳做法。通过学习,读者将能运用Go语言构建高效、实时的Web应用。
|
6天前
|
算法 Java Go
【Go语言专栏】Go语言中的泛型编程探索
【4月更文挑战第30天】Go语言新引入的泛型编程支持使得代码更通用灵活。通过类型参数在函数和接口定义中实现泛型,如示例中的泛型函数`Swap`和泛型接口`Comparator`。泛型应用包括数据结构、算法实现、函数包装和错误处理,提升代码复用与维护性。这一特性扩展了Go语言在云计算、微服务、区块链等领域的应用潜力。
|
6天前
|
存储 Go 开发者
【Go语言专栏】深入探索Go语言的接口与多态
【4月更文挑战第30天】本文探讨了Go语言中的接口和多态性。接口是方法集合的抽象类型,允许不同类型的值实现相同的方法,实现多态。接口定义不包含实现,仅包含方法签名。类型实现接口是隐式的,只要实现了接口所需的方法。接口用于编写与具体类型无关的通用代码。通过接口,不同类型的对象可以响应相同消息,展现多态性。此外,接口可以嵌入以继承其他接口,类型断言则用于访问接口内部的具体类型。空接口可存储任何类型值。理解并掌握接口有助于编写更灵活、模块化的Go代码。
|
6天前
|
SQL 关系型数据库 MySQL
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
|
6天前
|
网络协议 Linux Go
Go语言TCP Socket编程(下)
Go语言TCP Socket编程
|
6天前
|
网络协议 Ubuntu Unix
Go语言TCP Socket编程(上)
Go语言TCP Socket编程