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 ...
随机推荐
- Python中关于txt的简单读写模式与操作
Python中关于txt的简单读写操作 常用的集中读写模式: 1.r 打开只读文件,该文件必须存在. 2.r+ 打开可读写的文件,该文件必须存在. 3.w 打开只写文件,若文件存在则文件长度清为0,即 ...
- netty-1.从一个最简单的例子开始
(原) 第一篇,从一个最简单的例子开始 1.netty是干什么,怎么用,这里不作介绍,先从一个例子来了解它, netty 5.0以上的版本被废弃了,以下例子从4.1.10.Final版本开始. 2.一 ...
- lib异步中断
基于libusbx-1.0.18-rc1,libusbx现已重新merage到libusb.1. 初始化使用libusb_init初始化libusb,如果是单设备通信,ctx参数可以传NULL,表示使 ...
- windows安装PostgreSQL
犹豫了一小下,初学不在linux下安装sql,虽然说书上有,还是想记录一下,以后好找 入门的书籍是SQL基础教程第二版,图书馆搜刮来的,毕竟要还 下载页面 http://www.enterprised ...
- solr admin界面的监控
这里可以看到,solr的版本,lucene的版本,jvm的版本,CPU核数,jvm启动参数,还有物理内存占用,交换空间占用,jvm内存占用. 这里可以看到每个core的情况. 这里可以看到java的所 ...
- Maven 安装 与 使用
下载地址:http://maven.apache.org/download.cgi 下载完成后,配置环境变量 (前提 已经安装JDK )后才能使用. 进入 bin 目录 复制 路径 添加到环境变量中 ...
- Java-JsonUtil工具类
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; i ...
- SQL Prompt 5 功能按键说明
1. Refresh suggestions 未知,按了没反映 2.Format sql 标准化SQL代码书 ...
- 【Python之路】特别篇--生成器(constructor)、迭代器(iterator)、可迭代对象(iterable)
生成器(constructor) 生成器函数在Python中与迭代器协议的概念联系在一起.包含yield语句的函数会被特地编译成生成器 !!! 当函数被调用时,他们返回一个生成器对象,这个对象支持迭代 ...
- [Flask]sqlalchemy使用count()函数遇到的问题
sqlalchemy使用count()函数遇到的问题 在使用flask-sqlalchemy对一个千万级别表进行count操作时,出现了耗时严重.内存飙升的问题. 原代码: # 统计当日登陆次数 co ...