GO学习之 接口(Interface)

GO系列

1、GO学习之Hello World
2、GO学习之入门语法
3、GO学习之切片操作
4、GO学习之 Map 操作
5、GO学习之 结构体 操作
6、GO学习之 通道(Channel)
7、GO学习之 多线程(goroutine)
8、GO学习之 函数(Function)
9、GO学习之 接口(Interface)

文章目录

  • GO系列
  • 前言
  • 一、什么是接口(interface)?
  • 二、如何定义接口
  • 三、如何实现接口
    • 3.1 多个类型实现同一接口
    • 3.2 一个类型实现多个接口
    • 3.3 接口嵌套
    • 3.4 空接口
  • 四、接口与类型断言
  • 五、接口运用
  • 六、总结

前言

按照公司目前的任务,go 学习是必经之路了,虽然行业卷,不过技多不压身,依旧努力!!!
JAVA中我们可以使用interface来定义一个接口,抽离出来公共的字段和方法,再有不同的class来实现这些接口和接口中方法,来实现代码的解耦和灵魂,主要依据的就是JAVA的多态性,比如说在 Spring框架中,有 EventListener 接口,然后实现了此接口的有好多class(ContextRefreshListener、RestartListener…),每个实现类都有个子不同的功能。
那在 Go 语言中也有 interface,我们可以通过 interface来定义一种对象的行为规范,也就是定义了一组行为,不需要关注这些规范如何实现,我们可以通过接口将代码解耦,使得不同模块之间依赖减少,提高代码可维护性。

一、什么是接口(interface)?

  • interface 是一种类型,描述了对象的行为但是不关心实现
  • interface 只定义了方法,没有实现,有其他类型实现,是一组方法的集合
  • 接口提供了一种约定,告诉其他类型实现这些方法即可满足接口的要求
  • 不像其他语言中的接一样需要显式地声明实现了哪些接口,Go 语言中的实现是隐式的,只要一个类型实现了接口中定义的所有方法,就视为该类型实现了接口

二、如何定义接口

  • 接口的定义语法:type {interfaceName} interface { MethodName(paramName paramType) returnType },比如:type Runner interface{ run(name string) string }
  • 接口中的方法只有方法名、参数列表和返回值类型,没有方法体
  • 接口中方法的参数和返回值可以是任何类型,包括 interface 类型(强调:interface 是一种类型
  • 接口中方法可以有多个返回值,比如:type Shape interface {Area() (float64, error)}
  • 接口定义中方法名称和参数列表组成了接口的签名

三、如何实现接口

  • 如果一个类型实现了接口中定义的所有方法,就视为该类型实现了接口
  • 如果一个类型实现了某个接口,那么可以将该类型的实现赋值给接口类型变量
  • 一个类可以实现多个接口

3.1 多个类型实现同一接口

此例子中,定义了一个 Shape 的接口,这个接口提供了 Area 方法用来求图形的面积,分别定义矩形(Rectangle)和 圆形(Circle)两个结构体,并且实现了 Shape 中的 Area 方法,初始化矩形和圆形并且调用 Area 方法求出面积。

package mainimport "fmt"// 定义一个图形接口,方法是求图形的面积
type Shape interface {Area() float64
}// 定义一个矩形
type Rectangle struct {Width  float64Height float64
}// 矩形实现了 Shape 接口中求面积的 Area 方法
func (r Rectangle) Area() float64 {return r.Width * r.Height
}// 定义一个圆形
type Circle struct {Radius float64
}// 圆形实现了 Shape 接口中求面积的 Area 方法
func (c Circle) Area() float64 {return 3.14 * c.Radius * c.Radius
}func main() {// 定义一个接口类型变量var shape Shape// 创建一个矩形并赋值给接口 shapeshape = Rectangle{Width: 5, Height: 10}fmt.Printf("矩形的面积是:%+v\n", shape.Area())// 创建一个圆形并赋值给接口 shapeshape = Circle{Radius: 3}fmt.Printf("圆形的面积是:%+v\n", shape.Area())
}

运行结果:

PS D:\workspaceGo\src\interface> go run .\interfaceTest.go
矩形的面积是:50
圆形的面积是:28.259999999999998

3.2 一个类型实现多个接口

此例子中,定义了两个接口,分别是 ShapeArea(求面积) 和 ShapeRound(求周长) 两个接口,实例化了 Sequre 类型并且赋值给两个接口,调用各自接口方法

package mainimport "fmt"// 定义一个图形接口,方法是求图形的面积
type ShapeArea interface {Area() float64
}// 定一个图形接口,方法是求图形周长
type ShageRound interface {Round() float64
}// 定义一个正方形
type Sequre struct {Side float64
}// 正方形实现了 ShapeArea 接口中求面积的 Area 方法
func (s Sequre) Area() float64 {return s.Side * s.Side
}// 正方形实现了 ShapeRound 接口中周长 Round 的方法
func (s Sequre) Round() float64 {return 4 * s.Side
}func main() {// 定义接口var spaceArea ShapeAreavar spaceRound ShageRound// 实例化 Sequre 结构体s := Sequre{Side: 9}// 赋值给接口 spaceArea 以求面积spaceArea = sfmt.Printf("正方形的面积是:%+v\n", spaceArea.Area())// 赋值给接口 spaceRound 以求周长spaceRound = sfmt.Printf("正方形的周长是:%+v\n", spaceRound.Round())
}

运行结果:

PS D:\workspaceGo\src\interface> go run .\interfaceTest2.go
正方形的面积是:81
正方形的周长是:36

3.3 接口嵌套

此示例中,定义了两个接口 Sayer 和 Mover ,为了方便其他类型是,又定义了一个接口 Animal 嵌套了 Sayer 和 Mover 两个接口,基于两个接口的规则一自身,然后定义了 Cat 结构体类型,实例化之后赋值给了 Animal 变量 ‘yuanbao’,元宝是之前养过的一只很有灵性的黑白猫,元宝就可以叫,还可以上蹿下跳了。

package mainimport "fmt"// 定义接口 表示可以说话
type Sayer interface {say()
}// 定义接口,表示可以移动
type Mover interface {move()
}// 接口嵌套
type Animal interface {SayerMover
}// 定义结构体类型 猫咪
type Cat struct {Name string
}// 定义猫咪叫的方法
func (c Cat) say() {fmt.Printf("喵咪 %+v 在叫'喵喵喵'\n", c.Name)
}// 定义猫咪动的方法
func (c Cat) move() {fmt.Printf("猫咪 %+v 在上蹿下跳\n", c.Name)
}func main() {var yuanbao Animalyuanbao = Cat{Name: "元宝"}yuanbao.say()yuanbao.move()
}

运行结果:

PS D:\workspaceGo\src\interface> go run .\interfaceNested.go
喵咪 元宝 在叫'喵喵喵'
猫咪 元宝 在上蹿下跳

3.4 空接口

此示例中定义了一个空接口,既然接口是一种类型,不关心实现,那我们可以借助空接口来实现接受任何类型参数,类似于JAVA中的 Object 超类,可以接受任何参数,可以作为函数的参数,也可以放在 map 中以便此 map 存放任何类型的值。

package mainimport "fmt"// 定义一个空接口
type Object interface{}// 定义一个函数,接受任何类型参数
func show(o interface{}) {fmt.Printf("type: %T, value: %+v\n", o, o)
}func main() {show(100)show("phan日复一日,刻苦学习,成就大业!")// 定义一个 Map, key为字符串,值为任何类型var myInfo = make(map[string]interface{})myInfo["name"] = "phen"myInfo["age"] = 25myInfo["hobby"] = "运动,看书,数钱"myInfo["rich"] = falsefmt.Printf("phen的个人信息:%+v\n", myInfo)
}

运行结果:

PS D:\workspaceGo\src\interface> go run .\interfaceEmpty.go
type: int, value: 100
type: string, value: phan日复一日,刻苦学习,成就大业!
phen的个人信息:map[age:25 hobby:运动,看书,数钱 name:phen rich:false]

四、接口与类型断言

  • 类型断言是将接口类型转换为其他类型的操作
  • 类型断言有两种方式:1、value, ok := x.(T),2、value := x.(T)
  • 类型断言可以判断接口类型是否实现了某个接口
  • 类型断言可以判断接口类型是否是某个具体类型
package mainimport "fmt"// 定义一个图形接口,方法是求图形的面积
type Shape interface {Area() float64
}// 定义一个矩形
type Rectangle struct {Width  float64Height float64
}// 矩形实现了 Shape 接口中求面积的 Area 方法
func (r Rectangle) Area() float64 {return r.Width * r.Height
}func main() {// 定义一个接口类型变量var shape Shape// 接口断言,如果 ok = true, 则 rect 的类型为 Rectangleif rect, ok := shape.(Rectangle); ok {fmt.Printf("矩形的面积为 %+v\n", rect.Area())} else {fmt.Println("接口 shape 不包含 Rectangle 的值")}// 创建一个矩形并赋值给接口 shapeshape = Rectangle{Width: 5, Height: 10}// 接口断言,如果 ok2 = true, 则 r 的类型为 Rectangleif r, ok2 := shape.(Rectangle); ok2 {fmt.Printf("矩形的面积是:%+v\n", r.Area())} else {fmt.Println("接口 shape 不包含 Rectangle 的值")}
}

运行结果:

PS D:\workspaceGo\src\interface> go run .\interfaceTest.go 
接口 shape 不包含 Rectangle 的值
矩形的面积是:50

从运行结果看,在没有给接口 shape 赋值的时,断言 ok 是 false,下面给接口类型变量 shape 正式赋值了,则成功执行了 r.Area() 计算了面积。

五、接口运用

  • 接口类型可以作为函数的参数接受参数
  • 接口类型可以是任意类型作为 map、结构体等的 value
  • 接口类型可以让代码解耦
  • 利用接口可以进行提取和抽离出来公共模块,提高开发效率
  • 等…

六、总结

接口类型在 Go 语言中是非常重要的特性,它提供了一种约定和抽象的方式,让不同的类型可以用相同的方式处理。在实际开发中有许多用途和场景,重要包括:

  1. 实现多态性:让不同类型以相同方式处理,提高代码的灵活性和复用性
  2. 解耦代码:通过接口将代码解耦,使得不同模块直接依赖较少,从而提高代码的可维护性
  3. 实现设计模式:接口类型可以很好的支持如 工厂模式、策略模式等这些模式的实现,让代码更加简洁易于维护和理解
  4. 扩展性和适配器模式:通过接口,可以很好的扩展程序的功能,只需实现相应的方法即可,同时接口也可以适用于不同的模块,将不同的类型适配成统一的接口类型,实现代码的复用和扩展
  5. 测试和模拟:在单元测试中,可以利用接口来模拟依赖项,实现代码的测试隔离。通过使用接口,可以方便的替换真实的依赖实现,从而实现对代码的独立测试

总而言之,接口类型在 Go 语言中非常灵活和强大,它可以帮助我们实现面向接口编程,提高代码的灵活性和可复用性,减少代码的耦合性,使得代码更加清晰、简洁和易于维护。在实际开发中,合理地使用接口类型,可以使代码更加健壮和可扩展,提高开发效率和质量。

现阶段还是对 Go 语言的学习阶段,想必有一些地方考虑的不全面,本文示例全部是亲自手敲代码并且执行通过。
如有问题,还请指教。
评论去告诉我哦!!!一起学习一起进步!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/31419.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是MVCC

问题描述 对于 MVCC 的理解,我觉得可以先从数据库的三种并发场景说起: 第一种:读读 线程 A 与线程 B 同时在进行读操作,这种情况下不会出现任何并发问题。 第二种:读写 线程 A 与线程 B 在同一时刻分别进行读和写…

W5100S-EVB-PICO 做TCP Server进行回环测试(六)

前言 上一章我们用W5100S-EVB-PICO开发板做TCP 客户端连接服务器进行数据回环测试,那么本章将用开发板做TCP服务器来进行数据回环测试。 TCP是什么?什么是TCP Server?能干什么? TCP (Transmission Control Protocol) 是一种面向连…

十一、结合数字孪生与时间技术进行多维分析设计与实施

大数据可视化中心以主题为分析对象,选择业务分类下的某个主题,可以在数据面板中展示其二维图表,在地图中标记其空间分布,并叠加其相应的二维或三维图层。 1、界面设计 其主界面设计详上图,各部分功能介绍如下: 1.1、主题与图层面板,从上到下,从左到右分别是: ①折…

【1++的数据结构】之二叉搜索树

👍作者主页:进击的1 🤩 专栏链接:【1的数据结构】 文章目录 一,什么是二叉搜索树二,二叉搜索树的操作及其实现2.1 插入操作及其实现2.2 查找操作及其实现2.3 删除操作及其实现 三,构造及其析构四…

分布式链路追踪概述

分布式链路追踪概述 文章目录 分布式链路追踪概述1.分布式链路追踪概述1.1.什么是 Tracing1.2.为什么需要Distributed Tracing 2.Google Dapper2.1.Dapper的分布式跟踪2.1.1.跟踪树和span2.1.2.Annotation2.1.3.采样率 3.OpenTracing3.1.发展历史3.2.数据模型 4.java探针技术-j…

TOMCAT部署及优化(Tomcat配置文件参数优化,Java虚拟机(JVM)调优)

TOMCAT tomcat :是一个开放源代码的web应用服务器,基于java代码开发的。也可以理解为tomacat就是处理动态请求和基于java代码的页面开发。可以在html当中写入java代码,tomcat可以解析html页面当中的java,执行动态请求,…

Java算法_ LRU 缓存(LeetCode_Hot100)

题目描述:请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 获得更多?算法思路:代码文档,算法解析的私得。 运行效果 完整代码 import java.util.HashMap; import java.util.Map;/*** 2 * Author: L…

makefile include 使用介绍

文章目录 前言一、include 关键字1. 语法介绍2. 处理方式示例: 二、- include 操作总结 前言 一、include 关键字 1. 语法介绍 在 Makefile 中,include 指令: 类似于 C 语言中的 include 。将其他文件的内容原封不动的搬入当前文件。 当 …

打破音频语言障碍,英语音频翻译成文字软件助你畅快对话

要理解外语歌曲对我来说难如登天。不过,这种痛苦没有持续太久,我发现了一种音频翻译技术,它像一个语言转换器,可以即时将外语歌曲翻译成我听得懂的语言!我惊喜地试用后,终于可以在听歌的同时看到翻译的歌词…

QT压缩解压文件

文章目录 前言一、下载Quazip二、编译Quazip1.使用vs2019打开quazip.sln2.使用Qt VS Tools打开外层的.pro工程3.编译 三、工程使用1.配置头文件路径2.配置静态库lib目录3.添加库4.动态库dll放到.exe同级目录下5.使用 前言 Qt工程中需要用到zip压缩解压功能,网上搜索…

C++类型查询模板之std::is_array

2023年8月10日&#xff0c;周四上午 概述 std::is_array是一个C类型查询(type trait)模板,它可以用来判断一个类型是否是数组类型。 std::is_array定义在头文件<type_traits>中。 使用方法 可以通过std::is_array::value成员常量来判断一个类型是否是数组类型。 std:…

【Tool】win to go 制作随身硬盘

前言 话说我一冲动买了512G固态硬盘&#xff0c;原本是装个ubuntu系统的&#xff0c;这个好装&#xff0c;但是用处太少&#xff0c;就像改成win10的 经历一堆坑之后&#xff0c;终于使用WTG安装好了 步骤 1.下载个WTG辅助工具 Windows To Go 辅助工具|WTG辅助工具 v5.6.1…

leetcode - 75. 颜色分类(java)

颜色分类 leetcode - 75. 颜色分类题目描述双指针代码演示 双指针算法专题 leetcode - 75. 颜色分类 难度 - 中等 原题链接 - 颜色分类 题目描述 给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums &#xff0c;原地对它们进行排序&#xff0c;使得相同颜色的元素相邻&…

容器化相关面试题

Docker相关面试题 (1)Docker的组件包含哪些? 客户端:dockerclient服务端:dockerserver## 能看到相关的信息 docker info## docker client向docker daemon发送请求,docker daemon完成相应的任务,并把结果返还给容器 Docker镜像: docker镜像是一个只读的模板,是启动一…

【安装部署】Mysql下载及其安装的详细步骤

1.下载压缩包 官网地址&#xff1a;www.mysql.com 2.环境配置 1.先解压压缩包 2.配置环境变量 添加环境变量&#xff1a;我的电脑--->属性-->高级-->环境变量-->系统变量-->path 3.在mysql安装目录下新建my.ini文件并&#xff0c;编辑my.ini文件 编辑内容如…

Centos7.9安装lrzsz进行文件传输---Linux工作笔记059

这里咱们lrzsz命令,需要用来进行文件传输,因为如果不安装这个命令的话,那么 传输安装包什么的就不方便因为只有少数传输工具,才支持,直接拖拽的.没有的时候就可以用这个工具,用命令来传输 直接就是: sz 文件名 就可以把文件下载下来 rz 选择一个文件, 就可以把文件上传到当…

SpringMVC简介搭建环境快速入门

1.简介 SpringMVC是一个基于Spring开发的MVC轻量级框架&#xff0c;Spring3.0后发布的组件&#xff0c;SpringMVC和Spring可以无 缝整合&#xff0c;使用DispatcherServlet作为前端控制器&#xff0c;且内部提供了处理器映射器、处理器适配器、视图解析器等组 件&#xff0c;可…

F12诡异Bug分享

Bug本身情况 java运行的时候会产生class文件&#xff0c;其本身是跑class文件的&#xff0c;但某个实施反馈一个经典版本的长久bug。 当使用模糊查询时&#xff0c;一页一页查看&#xff0c;在倒数第二页时&#xff0c;点击下一页&#xff0c;页面静止不动。&#xff08;正常情…

FISCO BCOS V3.0 Air建链体验——对比V2.9建链差别

前提 好久不见&#xff0c;最近因为毕业的手续等问题&#xff0c;一直都没有更新&#xff0c;FISCO BCOS第二季task挑战赛如期展开啦&#xff0c;因为毕业的问题&#xff0c;也是非常遗憾的错过了上一期的task挑战赛&#xff0c;这一期一定双倍挑战&#xff0c;hhhhhh Air版本…

面试热题(单词搜索)

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格是那些水平相邻或垂直相…