golang(10)interface应用和复习
原文链接 http://www.limerence2017.com/2019/10/11/golang15/
interface 意义?
golang 为什么要创造interface这种机制呢?我个人认为最主要的就是做约束,定义一种规范,大家可以按照同一种规范实现各自的功能,从而实现多态。
同时当interface做函数形参,可以很好地限制传入参数,并且根据不同的实参调用达到多态的效果。多态的意思就是多种多样的功能,比如我们定义了一
个接口
1 |
type IOInter interface{ |
定义了一个IOInter的接口,只要别人实现了write和read方法,都可以转化为这个接口。至于具体怎么读,读什么,网络IO还是文件IO取决于具体的实现,
这就形成了多样化的功能,从而实现多态。同时IOInter做函数的形参,
1 |
func WriteFunc(io IOInter){ |
还达到了安全限制的功能。比如没有实现读写功能的类实例无法传给WriteFunc,WriteFunc内部调用io的Write函数会根据实参具体的实现完成特定的读写。
我们通过一个小例子实战下接口做形参的意义。golang中sort包提供了几个排序api,我们先实现一个int类型slice排序功能。
1 |
arrayint := []int{6, 1, 0, 5, 2, 7} |
sort.Ints可以完成对整形slice的排序,同样sort.Strings可以完成对string类型slice的排序
1 |
arraystring := []string{"hello", "world", "Alis", "and", "Bob"} |
如果有这样一个需求,游戏中有很多个英雄,每个英雄有四个属性,攻击,防御,名字,出生时间,对这些英雄排序,从小到大,优先按照攻击排序,其次攻击相等的按
照防御排序,如果防御相等的按照出生时间排序。这是比较规则,我们根据sort包的Sort函数可以实现这个功能。
首先我们先定义英雄的结构
1 |
type Hero struct { |
其次我们再定义一个英雄列表
1 |
type HeroList []*Hero |
接下来,我们看看golang的sort包实现的Sort源码
1 |
func Sort(data Interface) { |
可以看出,Sort函数有一个Interface类型的形参,我们继续查看Interface的类型
1 |
type Interface interface { |
可以看出Interface是一个接口,内部声明了三个方法Len,Less,Swap.
我们需要给自己的英雄列表实现这三个方法,就可以调用Sort排序了。先实现Len方法。
1 |
func (hl HeroList) Len() int { |
Len功能很简单,就是实现了列表大小的获取。接下来实现比较函数Less,Less是按照我们之前说的英雄比较规则实现
1 |
func (hl HeroList) Less(i, j int) bool { |
优先判断攻击是否相等,不相等就按照攻击力大小排序,小于返回true,从而实现从小到大排序
其次,攻击相等按照防御排序,以此类推。
接下来实现交换函数,交换英雄列表中的两个英雄
1 |
func (hl HeroList) Swap(i, j int) { |
这样,我们的英雄列表功能和结构都设计好了,写个main函数测试下
1 |
//自定义类型排序用sort.Sort |
我们通过for循环,每一秒生成一个英雄,攻击力和防御力随机,然后调用sort排序,接下来打印下看看效果
1 |
Hero1570780749 11 45 1570780749 |
看的出来,优先按照攻击力排序,攻击力相同则按照防御值排序。这样,这个排序的小功能就做好了。
interface万能接口
interface{}空接口可以接受任何类型的变量,从而可以实现类似于泛型编程的功能。golang本身并不支持泛型,原作者说泛型编程太过复杂,
以后会更新进来。
interface{}类型的变量在使用时要转化为具体的类型,否则会报错。转化方法前文提起过,现在复习一遍
1 |
var ife interface{} |
herolists是上个例子定义的英雄列表,将它赋值给ife后,ife为interface{}类型,不能直接使用,所以用ife.(HeroList)来转换为HeroList
类型。
当然interface{}还可以做类型判断
1 |
func JudgeType(itf interface{}) { |
interface实现万能类型双向链表
基于上面的知识,我们再做一个例子,实现双向链表,支持头部插入,尾部插入,指定位置插入,指定位置删除,可存储任意类型数据
我们先定义链表的基本结构
1 |
type LinkList struct { |
LinkeEle是链表中的每个节点类型,包含Data数据域,其为interface{}类型,以及Pre指向前一个节点的指针,Next指向后一个节点的指针。
LinkList是链表结构,包含头和尾部节点的指针
好的,为了方便取出节点数据域,我们给LinkEle实现一个GetData方法。
1 |
func (le *LinkEle) GetData() interface{} { |
接下来我们实现插入操作,实现头部插入,基本思路为在头部节点前插入新节点,然后将新节点和头部节点连接,更新新节点为头部节点
1 |
func (ll *LinkList) InsertHead(le *LinkEle) { if ll.Tail == nil && ll.Head == nil { |
上面先判断链表是否为空,如果链表为空,那么直接更新头尾信息即可,否则就需要执行连接操作。同样的道理我们实现尾部插入
尾部插入实在尾部节点的后边插入
1 |
func (ll *LinkList) InsertTail(le *LinkEle) { |
我们测试下实现的功能
1 |
ll := &LinkList{nil, nil} |
我们初始化了一个LinkList类型的链表变量ll,然后在头部插入两个节点,在尾部插入两个节点,看看效果
1 |
insert head ..................... |
头部插入先插入81,然后插入87,所以列表变为87,81
接着尾部插入47,59,列表变为87,81,47,59
接下来实现在指定位置的节点后插入节点
1 |
func (ll *LinkList) InsertIndex(le *LinkEle, index int) { |
首先判断链表是否为空,如果为空,则直接更新节点为列表头尾节点。否则判断插入位置是否越界,如果越界则直接返回。
如果不越界,则将节点插入,并判断插入节点是否为最后位置,如果为最后位置,则更新其为尾结点。
接下来我们测试在第三个节点后边插入节点。补充代码如下,前边的插入不变,看下效果
1 |
fmt.Println("insert after third element........") |
结果如下
1 |
insert head ..................... |
前边是头部和尾部插入的输出,接着我们在第三个位置节点后插入81,打印看到确实插入在了47的后边。
同样我们接下来实现删除操作,删除指定位置的节点
1 |
func (ll *LinkList) DelIndex(index int) { |
和插入操作类似,判断是否为空链表,是否只有一个节点等情况,接着判断删除的是否为头结点,是否为尾节点,否则就执行删除后的连接操作。
继续上边的测试代码,我们添加如下测试代码补充测试
1 |
fmt.Println("delete second element, its index is 1") |
输出如下
1 |
87 |
我们删除了index为1,也就是第二个节点81,测试成功了。
由于链表的数据域Data为空接口类型,所以可以存储各种类型的数据,只需要在GetData时做具体类型转换即可。
接下来读者可以自己考虑实现删除头部节点,删除尾部节点等。
可以下载我的源码 :
https://github.com/secondtonone1/golang-/tree/master/day26
总结
本文通过两个小例子实战,演示了interface常用的用法,为接下来讲解反射做铺垫。
感谢关注我的公众号
golang(10)interface应用和复习的更多相关文章
- Golang的Interface是个什么鬼
问题概述 Golang的interface,和别的语言是不同的.它不需要显式的implements,只要某个struct实现了interface里的所有函数,编译器会自动认为它实现了这个interfa ...
- golang 关于 interface 的学习整理
Golang-interface(四 反射) go语言学习-reflect反射理解和简单使用 为什么在Go语言中要慎用interface{} golang将interface{}转换为struct g ...
- golang的interface剖析
背景: golang的interface是一种satisfied式的.A类只要实现了IA interface定义的方法,A就satisfied了接口IA.更抽象一层,如果某些设计上需要一些更抽象的 ...
- Golang 的 `[]interface{}` 类型
Golang 的 []interface{} 类型 我其实不太喜欢使用 Go 语言的 interface{} 类型,一般情况下我宁愿多写几个函数:XxxInt, XxxFloat, XxxString ...
- Golang接口(interface)三个特性(译文)
The Laws of Reflection 原文地址 第一次翻译文章,请各路人士多多指教! 类型和接口 因为映射建设在类型的基础之上,首先我们对类型进行全新的介绍. go是一个静态性语言,每个变量都 ...
- Golang-interface(四 反射)
github:https://github.com/ZhangzheBJUT/blog/blob/master/reflect.md 一 反射的规则 反射是程序执行时检查其所拥有的结构.尤其是类型的一 ...
- golang之interface
一.概述 接口类型是对 "其他类型行为" 的抽象和概况:因为接口类型不会和特定的实现细节绑定在一起:很多面向对象都有类似接口概念,但Golang语言中interface的独特之处在 ...
- golang将interface{}转换为struct
项目中需要用到golang的队列,container/list,需要放入的元素是struct,但是因为golang中list的设计,从list中取出时的类型为interface{},所以需要想办法把i ...
- Golang-interface(二 接口与nil)
github: https://github.com/ZhangzheBJUT/blog/blob/master/nil.md 一 接口与nil 前面解说了go语言中接口的基本用法,以下将说一说nil ...
随机推荐
- docker安装rocketmq
一.单机部署 1.拉取镜像:foxiswho/rocketmq:server cabel/rocketmq:broker styletang/rocketmq-console-ng 2.创建目录:d ...
- Pandas中DataFrame数据合并、连接(concat、merge、join)之join
pandas.DataFrame.join 自己弄了很久,一看官网.感觉自己宛如智障.不要脸了,直接抄 DataFrame.join(other, on=None, how='left', lsuff ...
- 题解 【NOI2015】软件包管理器
题面 解析 事实上,这应该是道树剖裸题了, 将已安装表示为\(1\), 那么只需要在线段树中记录一下区间中\(1\)的个数就行了. 在询问的时候, 如果是安装,就查询\(x\)到根节点, 卸载的话,就 ...
- 【Winform-自定义控件】DataGridView 单元格合并和二维表头
DataGridView单元格合并和二维表头应用: //DataGridView绑定数据 DataTable dt = new DataTable(); dt.Columns.Add("); ...
- keras中常用的初始化器
keras中常用的初始化器有恒值初始化器.正态分布初始化器.均匀分布初始化器 恒值初始化器: keras.initializers.Zeros() keras.initializers.Ones() ...
- 2018蓝桥杯C/C++组第4题第几个幸运数
题目4标题:第几个幸运数 到x星球旅行的游客都被发给一个整数,作为游客编号.x星的国王有个怪癖,他只喜欢数字3,5和7.国王规定,游客的编号如果只含有因子:3,5,7,就可以获得一份奖品. 我们来看前 ...
- 2019暑假集训 windy数
题目描述 Windy 定义了一种 Windy 数:不含前导零且相邻两个数字之差至少为2的正整数被称为 Windy 数. Windy 想知道,在A和B之间,包括A和B,总共有多少个 Windy 数? 输 ...
- [洛谷P3941]:入阵曲(前缀和+桶)
题目传送门 题目背景 丹青千秋酿,一醉解愁肠.无悔少年枉,只愿壮志狂. 题目描述 小$F$很喜欢数学,但是到了高中以后数学总是考不好.有一天,他在数学课上发起了呆:他想起了过去的一年.一年前,当他初识 ...
- linux安装vlc视频播放器
文章来自转发 最近,打算在centos7.2上安装一个叫MPlayer的视频播放器,但是折腾好久,得到的结果只是可以播放,但是却没有声音.无奈之下另寻他路.最后选择安装VLC视频播放器. 我的linu ...
- elasticsearch与kibana安装过程(linux)
elasticsearch与kibana安装 下载 Elasticsearch 官网:https://www.elastic.co/,elastic search应用本质就是一个jvm进程,所以需要J ...