一篇文章带你了解Go语言基础之接口(上篇)

开发 后端
本篇我们学习Go基础的接口,主要学习了接口和继承的区别,一个结构体实现多个接口,接口嵌套。

 前言

Hey,大家好呀,我是码农,星期八,之前怎么学到过面向对象的相关知识,但是还差一点,差了个接口。

并且接口在代码中用的还是比较多的,一起来看看吧!

什么是接口(interface)

这里的接口,可不是说那种插槽的那种接口,互相怼到一块就完事了。

在各种语言中,提到接口,通常指的之一种规范,然后具体对象来实现这个规范的细节。

本文使用的接口主要是约束接口,还有一种存储接口。

注:

在Go中,接口(interface)是一种类型,一种抽象类型,它只有方法,没有属性。

为什么需要接口

我们在讲结构体时,Go语言基础之结构体(春日篇)、Go语言基础之结构体(夏日篇)、Go语言基础之结构体(秋日篇),提到过继承这个概念,Go是通过结构体来完成继承的。

回顾继承

车结构体

  1. //车 
  2. type Car struct { 
  3.     Brand  string //车品牌 
  4.     CarNum string //车牌号 
  5.     Tyre   int    //轮胎个数 
  6.  
  7. //给车绑定一个方法,说明车的基本信息 
  8. func (this *Car) carInfo() { 
  9.     fmt.Printf("品牌:%s,车牌号:%s,轮胎个数:%d\n", this.Brand, this.CarNum, this.Tyre) 

车结构体有四个属性,同时还有一个显示车(carInfo)信息的方法。

宝马车

  1. //宝马车 
  2. type BMWCar struct { 
  3.     //*Car和Car基本没有区别,一个存的是整个结构体,一个存的是结构体地址,用法大同小异 
  4.     *Car //这就表示继承了Car这个结构体 

比亚迪车

  1. //比亚迪车 
  2. type BYDCar struct { 
  3.     *Car 

main代码

  1. func main() { 
  2.     //一个宝马对象 
  3.     var bmw1 = BMWCar{&Car{ 
  4.         Brand:  "宝马x8", 
  5.         CarNum: "京666", 
  6.         Tyre:   4, 
  7.     } 
  8.     //一个比亚迪对象 
  9.     var byd1 = BYDCar{&Car{ 
  10.         Brand:  "比亚迪L3", 
  11.         CarNum: "京111", 
  12.         Tyre:   4, 
  13.     } 
  14.     //因为 BMWCar 和 BYDCar 都继承了Car,所以都有carInfo这个方法 
  15.     bmw1.carInfo() 
  16.     byd1.carInfo() 

执行结果

 

通过回顾,我们可以发现,车,应该作为一个基本的概念。

上述Car结构体似乎显示了车的属性,其实是不太对的。

车就是一个抽象的概念,电瓶车是车,小轿车也是车,大卡车也是车。

这些车至少有一个统一的功能,那就是跑,但是像几个轮胎了,什么品牌了。

应该是属于自己的,不再是属于Car这个抽象的概念中了,所以,这时候用接口会更好。

定义接口

车接口

  1. type Car interface { 
  2.     //车会跑 
  3.     Run(speed int
  4.     //车需要加油 
  5.     Refuel(oil int
  6.     //车需要转弯 
  7.     Wheel(direction string) 

假设车,至少有这三个动作,不管任何结构体,只要实现了Car里面的所有方法,就代表它一定是一个车。

宝马车

  1. //宝马车 
  2. type BMWCar struct { 
  3.     Owner  string //车主 
  4.     Brand  string //车品牌 
  5.     CarNum string //车牌号 
  6. //构造方法 
  7. func NewBMWCar(owner string, brand string, carNum string) *BMWCar { 
  8.     return &BMWCar{Owner: owner, Brand: brand, CarNum: carNum} 
  9.  
  10. func (this *BMWCar) Run(speed int) { 
  11.     fmt.Printf("我是 %s,我的车是 %s,我车牌号为 %s,我正在以 %d 速度行驶\n", this.Owner, this.Brand, this.CarNum, speed) 
  12.  
  13. func (this *BMWCar) Refuel(oil int) { 
  14.     fmt.Printf("老板,加%d升油\n", oil) 
  15.  
  16. func (this *BMWCar) Wheel(direction string) { 
  17.     fmt.Printf("我正在%s转弯\n", direction) 

电瓶车

  1. //电瓶车 
  2. type Electromobile struct { 
  3.     Owner string //车主 
  4.     Brand string //车品牌 
  5.  
  6. func NewElectromobile(owner string, brand string) *Electromobile { 
  7.     return &Electromobile{Owner: owner, Brand: brand} 
  8. func (this *Electromobile) Run(speed int) { 
  9.     fmt.Printf("我是 %s,我的车是 %s,我正在以 %d 速度行驶\n", this.Owner, this.Brand,, speed) 
  10.  
  11. func (this *Electromobile) Refuel(oil int) { 
  12.     fmt.Printf("你妹的,你电动车加啥油...\n"
  13.  
  14. func (this *Electromobile) Wheel(direction string) { 
  15.     fmt.Printf("我正在%s转弯\n", direction) 

这里是有区别的,电瓶车没有属性CarNum,但是仍然实现了Car接口的所有方法,所以电瓶车在代码上,仍然是车。

main

  1. func main() { 
  2.     var 张三的车 Car 
  3.     张三的车 = NewBMWCar("张三", "宝马6", "京666"
  4.     张三的车.Run(80) 
  5.     张三的车.Refuel(20) 
  6.     张三的车.Wheel("左"
  7.  
  8.     var 李四的车 Car 
  9.     李四的车 = NewElectromobile("李四", "小刀电动车"
  10.     李四的车.Run(40) 
  11.     李四的车.Refuel(0) 
  12.     李四的车.Wheel("左"

第2行代码和第8行代码,变量类型是Car接口类型,但是在赋值时,确是其他类型。

Go是强类型语言,为什么类型不一致,还可以赋值,那执行结果会出问题吗???

执行结果

但是我们发现执行结果是没问题的。

但是为啥变量类型不一致,还是可以进行赋值并且每报错呢?

我们上述代码可以确定宝马车和电瓶车完全实现了Car接口里面所有的方法。

所以可以理解为Car就是他们的爸爸,用他们的爸爸来接收儿子,当然可以咯。

一个结构体实现多个接口

以下代码没有实际意义,完全是为了语法而语法。

接口代码

  1. //跑接口 
  2. type Runer interface { 
  3.   Run() 
  4.  
  5. // 跳接口 
  6. type Jumper interface { 
  7.   Jump() 

结构体代码

  1. //袋鼠结构体 
  2. type Roo struct { 
  3.   Name string 
  4.  
  5. func (this *Roo) Jump() { 
  6.   fmt.Println("我是袋鼠,我会跳"
  7.  
  8. func (this *Roo) Run() { 
  9.   fmt.Println("我是袋鼠,我会跑"

这个结构体同时实现了两个结构,一个是Runer,一个是Jumper。

main代码

  1. func main() { 
  2.   var runner Runer 
  3.   var jumper Jumper 
  4.  
  5.   runner = &Roo{Name"袋鼠"
  6.   jumper = &Roo{Name"袋鼠"
  7.  
  8.   runner.Run() 
  9.   jumper.Jump() 

Roo既然实现了两个接口,自然两个接口都可以接收Roo这个结构体。

执行结果


接口嵌套

接口嵌套这个有点像组合,比如有跑,跳,吃等这些操作。

例如一个动物,因该是要有这些操作的,那这个动物应该也是一个接口。

并且把这些动作都拿过来才对。

接口示例代码

  1. //跑接口 
  2. type Runer interface { 
  3.   Run() 
  4.  
  5. // 跳接口 
  6. type Jumper interface { 
  7.   Jump() 
  8.  
  9. //动物接口,继承了 跑 和 跳  
  10. type Animal interface { 
  11.   Runer 
  12.   Jumper 

结构体代码

  1. //袋鼠结构体,实现了跑和跳 
  2. type Roo struct { 
  3.   Name string 
  4.  
  5. func (this *Roo) Jump() { 
  6.   fmt.Println("我是袋鼠,我会跳"
  7.  
  8. func (this *Roo) Run() { 
  9.   fmt.Println("我是袋鼠,我会跑"

main代码

  1. func main() { 
  2.   var animal Animal 
  3.  
  4.   animal = &Roo{Name"袋鼠"
  5.   animal = &Roo{Name"袋鼠"
  6.  
  7.   animal.Run() 
  8.   animal.Jump() 

执行结果


总结

上述我们学习了Go基础的接口,主要学习了接口和继承的区别,一个结构体实现多个接口,接口嵌套。

可能不太好理解,但是一定要尝试做一下,一定要坚持!

 

责任编辑:姜华 来源: Go语言进阶学习
相关推荐

2020-10-25 07:33:13

Go语言

2022-02-16 10:03:06

对象接口代码

2020-12-09 09:59:32

Go语言技术

2020-11-05 09:58:16

Go语言Map

2020-10-22 08:33:22

Go语言

2020-11-11 10:52:54

Go语言C语言

2020-10-23 08:38:19

Go语言

2020-12-30 09:04:32

Go语言TCPUDP

2020-12-27 10:15:44

Go语言channel管道

2022-04-27 10:01:43

切片Go封装

2021-10-09 07:10:31

Go语言基础

2021-10-30 10:43:04

语言Go函数

2021-11-03 10:02:07

Go基础函数

2021-09-29 10:00:07

Go语言基础

2021-10-13 10:00:52

Go语言基础

2020-10-22 11:15:47

Go语言变量

2021-10-16 10:17:51

Go语言数据类型

2020-10-27 11:08:01

JavaScript

2020-12-23 08:39:11

Go语言基础技术

2021-09-27 09:18:30

ListIterato接口方法
点赞
收藏

51CTO技术栈公众号