序言

众所周知,Golang中不支持类似C++/Java中的标记式泛型,所以对于常用算法,比如冒泡排序算法,有些同学容易写出逻辑上重复的代码,即整型是第一套代码,字符串型是第二套代码,用户自定义类型是第三套代码。
重复是万恶之源,我们当然不能容忍,所以要消除重复,使得代码保持在最佳的状态。本文通过一个实际使用的简单算法的演进过程,初次体验了Golang的泛型编程,消除了重复代码,非常自然。

需求一:切片算法支持整型

今天是星期二,天气晴朗,万里无云,空气清新,我在办公室里听着音乐写着代码,开始了今天的工作。
“小哥,数组切片有没有add和remove函数,可以方便的将元素添加和删除?”
我抬头一看,是小明,就回答道:“什么类型的数组切片?”
小明说:“整型。”
”数组切片中的元素能不能有相同的?“我追问道。
”不能有相同的,我存的都是实体的Id。“小明肯定的回答。
“哦,这个简单,我过会提供一个Slice类,有Add和Remove方法,支持整型。”我有点自信的回答。
小明说完谢谢后,回到了办公位继续工作。

一个小时后,我写完了支持整型的切片算法(点击图片可查看大图):

小明看了我的实现后,说:”我试用一下?"

“丑媳妇不怕见公婆。“我请他试用。

小明用了5分钟,写了下面的代码:

从试用代码中可以看出,整型数组切片中最多有三个元素[1 2 3],元素2插入的第二次应该失败,同理元素2删除的第二次也应该失败,整型数组切片最后只剩下一个元素[1]。

go run运行代码后,日志如下:查看日志,结果符合期望。

需求二:切片算法支持字符串

周三下午,睡完午觉后精神有点小抖擞,浏览着邮件,突然发现公司又接了一个大单,于是吃了会精神食量。
”小哥,小哥!“
我抬头一看,是小雷。
”咋的啦,哥们?“我好奇的问道。
”听说你昨天实现了一个数组切片算法,已支持整型,我现在想用字符串型的数组切片算法,你能提供不?"小雷有点着急的问道。
我心里一想,Golang支持Any类型,即interface{},同时字符串和整型一样都可以直接用”==“运算符比较两个元素是否相等,所以你懂的。
”这个好实现,给我一首歌的时间就可以试用。“我说完后,就立刻修改起了代码。

两分钟后,我提供了新版本的代码:不难发现,改动很简单,只将三个地方的int改成了interface{},一切都是这么自然。

”哇塞,这么快?半首歌我还没听完。“小雷开森的说。
”简单设计,呵呵!“我们不约而同的说出了这个大家最爱说又最难做到的XP实践。

这次有了拷贝这个强大的武器,小雷两分钟就写完了试用代码:

从试用代码中可以看出,字符串型数组切片中最多有三个元素[hello golang generic],元素golang插入的第二次应该失败,同理元素golang删除的第二次也应该失败,字符串型数组切片最后只剩下一个元素[hello]。

查看日志,结果符合期望。

需求三:切片算法支持用户自定义的类型

今天周四,眼看明天就周五了,打算中午出去吃个自助餐提高一下生活质量,于是叫着小方开着车就杀出去了。由于在一点半之前要回到公司上班,所以匆匆地找了一家自助餐店。
“哇靠,人真多!”小方这样感叹道。
“这个店应该搞成多种模式,比如选取大家常吃的几种套餐(A,C,D),这样百分之七十的上班族都会直接领套餐,就不会白白浪费排队时间了。”我不着边际的边想边说。
“自助餐还是更有吸引力,顾客可以任意搭配,做到真正的私人订制,而套餐吃几次就腻味了。”小方反驳着对我说。
...
紧赶慢赶,终于,终于在一点半前回到了公司,于是又开始编码了。

“小哥,听说你实现了一个数组切片算法,既支持整型,又支持字符串型,我这还有一个小小需求。”
我抬头一看,是小方,就问“啥子需求?“
”我这边有自定义的struct类型,也想用数组切片算法。“小方大方的提出需求。
”这个嘛,这个嘛,有点难度!“我边思考边回应:”给我半个小时,让我试试。“
”好的,小哥。“小方说完后露出了惬意的笑。

我们先自定义一个类型:

Student类型有两个数据成员,即id和name。id是学号,全局我唯一;name是中文名字的拼音,可重复。

用户自定义类型和基本类型(int或string)不同的是两个元素是否相等的判断方式不一样:

  1. 基本类型(int或string)直接通过”==“运算符来判断;

  2. 用户自定义类型万千种种,数组切片算法中不可能知道,所以需要通过interface提供的方法进行两个元素是否相等的判断。

我们接着定义一个interface:

只要用户自定义的类型实现了接口Comparable,就可以调用它的方法IsEqual进行两个元素是否相等的判断了,于是我们实现了Student类型的IsEqual方法:

用户自定义的GetId方法是必要的,因为Id不一定就是数据成员,可能是由多个数据成员拼接而成。

我们将数组切片算法的易变部分”v == elem"抽出来封装成方法:于是数组切片的Add方法和Remove方法就变成:于是数组切片算法对于支持用户自定义类型的改动仅仅局限于isEqual函数了,我们通过接口查询来完成代码修改:半个小时后,我完成了代码,叫小方过来试用。

因为有拷贝这个强大的武器,小雷三分钟就写完了试用代码:从试用代码中可以看出,用户自定义类型的数组切片中最多有三个元素[{1001 xiao ming} {1002 xiao lei} {1003 xiao fang}],元素{1002 xiao lei}插入的第二次应该失败,同理元素{1002 xiao lei}删除的第二次也应该失败,用户自定义类型的数组切片最后只剩下一个元素[{1001 xiao ming}]。查看日志,结果符合期望。

小结

本文通过一种轻松愉快的方式阐述了实际使用的数组切片算法的演进过程,同时也是笔者使用Golang进行泛型编程的第一次旅行,再次领略了Golang中interface的强大魅力,希望对读者也有一定的启发

interface{} 泛型编程的更多相关文章

  1. C++ 模板与泛型编程

    <C++ Primer 4th>读书笔记 所谓泛型编程就是以独立于任何特定类型的方式编写代码.泛型编程与面向对象编程一样,都依赖于某种形式的多态性. 面向对象编程中的多态性在运行时应用于存 ...

  2. JAVA泛型编程笔记

    1介绍 Java泛型编程是JDK1.5版本后引入的.泛型让编程人员能够使用类型抽象,通常用于集合里面. 下面是一个不用泛型例子: List myIntList=new LinkedList(); // ...

  3. goalng nil interface浅析

    0.遇到一个问题 代码 func GetMap (i interface{})(map[string]interface{}){ if i == nil { //false ??? i = make( ...

  4. STL之父Stepanov谈泛型编程的发展史

    这是一篇Dr. Dobb's Journal对STL之父stepanov的采访.文中数次提到STL的基本思想.语言的特性.编程的一些根本问题等,非常精彩.这篇文章让我想去拜读下stepanov的大作& ...

  5. go 语言 interface{} 的易错点

    一,interface 介绍 如果说 goroutine 和 channel 是 go 语言并发的两大基石,那 interface 就是 go 语言类型抽象的关键.在实际项目中,几乎所有的数据结构最底 ...

  6. golang(10)interface应用和复习

    原文链接 http://www.limerence2017.com/2019/10/11/golang15/ interface 意义? golang 为什么要创造interface这种机制呢?我个人 ...

  7. Effective C++: 07模板与泛型编程

    C++ template机制自身是一部完整的图灵机(Turing-complete):它可以被用来计算任何可计算的值.于是导出了模板元编程(TMP, template metaprogramming) ...

  8. Go1.18中的泛型编程

    目录 目录 前言 泛型是什么 Go的泛型 泛型函数 泛型类型 类型集合 和接口的差异 总结 前言 经过这几年的千呼万唤,简洁的Go语言终于在1.18版本迎来泛型编程.作为一门已经有了14年历史的强类型 ...

  9. angular2系列教程(七)Injectable、Promise、Interface、使用服务

    今天我们要讲的ng2的service这个概念,和ng1一样,service通常用于发送http请求,但其实你可以在里面封装任何你想封装的方法,有时候控制器之间的通讯也是依靠service来完成的,让我 ...

随机推荐

  1. jquery中$.post()方法的简单实例

    在jqery中有这样一个方法,$.post()下面就这个方法做一个简单的实例: jQuery.post( url, [data], [callback], [type] ) :使用POST方式来进行异 ...

  2. 060、在docker中使用flannel(2019-03-29 周五)

    参考https://www.cnblogs.com/CloudMan6/p/7441188.html   配置docker 连接flannel   编辑host1的docker配置文件/etc/sys ...

  3. 学习go语言编程系列之定义变量

    package main import ( "fmt" "math") func main() { // 1. 定义变量名age,不初始化,使用对应类型的默认值 ...

  4. 指定so动态链接库连接器

    在学习x86_64汇编时, 发现一旦使用glibc库函数, 如printf时, 一般是需要使用为ld传递命令行参数-lc来动态连接libc.so的, 但是, 生成的可执行文件却无法运行: 气煞我也! ...

  5. Prolog 逻辑推导语言

    Prolog https://en.wikipedia.org/wiki/Prolog Prolog is a general-purpose logic programming language a ...

  6. git 完全讲解 无废话,包含在myeclipse中使用,包括解决冲突

    Git 1. Git简介 1.1 git是什么 1.1.1概念 Git:git是一款开源的分布式的版本控制软件 Github:是一个基于git的面向开源及私有软件项目的托管平台 因仅支持git 作为唯 ...

  7. Immunity Debugger学习 二

    1.Exploit开发 发现漏洞只是一个开始,在你完成利用程序之前,还有很长一段路要走.不过Immunity专门为了这项任务做了许多专门设计,相信能帮你减少不少痛苦.接下来我们开发一些PyComman ...

  8. luogu 1550 [Usaco2008 Oct]打井 最小生成树+小技巧

    此题似乎显然最小生成树,小技巧需要注意: 在每个点出井水,需要花费,实际上可以把井水视作所有井下统一的一点,需要走路径到达此点,新图上再最小生成树 将点化作边处理 还有题目写的数据范围一般不可信,开大 ...

  9. 卷积中的full、same、valid

    通常用外部api进行卷积的时候,会面临mode选择. 本文清晰展示三种模式的不同之处,其实这三种不同模式是对卷积核移动范围的不同限制. 设 image的大小是7x7,filter的大小是3x3     ...

  10. CDH5.12安装检查Inspector failed on the following hosts...

    1 安装检查报错 2 原因是因为自己的文件没有全部同步过去 hadoop003文件下面缺少了cm文件夹的内容 3 cp过去 scp -r cm root@hadoop003:/var/www/html ...