betterGo

天下苦golang久矣!

今亡亦死,举大计亦死,等死,死国可乎

背景

然而生活中,接收了没有泛型,似乎也挺美好的样子,直到某一天,你发现你又要对slice进行删除操作了,明明你前几天才做过的,明明…

泛型可以不用,但泛型库函数不能没有,我不想再写for了。美好的MapReduceuniq…,你们在哪里?

于是,betterGo诞生了

Implement golang generic by code generating like C++ template (monomorphization)

通过代码生成的方式,像C++ template一样,实现golang泛型函数(术语叫monomorphization)

正如之前文章国际劳动节,一起写一个linux初版的git吧里说的

我与两个师弟一起成立一个 git org,主要是他们(我需要工作,划水出主意做PM居多)做一些趣味使然的项目,PioneerIncubator[9],这个 git 是第三个项目,第一个项目是 betterGo,我好几个月前就写好初版了,就等他们做一些完善补充工作了,之后会单独介绍。第二个项目是刚动手,他们搜了一下,发现上年十月发现有人做了,那个项目还有500多star了

我起了个头,验证了可行性后,后续就交给z2z23n0开发了。(所以这个标题是我坑了他,哈哈哈

详情

C++的template实现的泛型,可以简单理解为在编译阶段,识别出其类型,不同的调用都实例化到具体的类型(就是每个泛型库函数都根据调用者的调用参数类型生成一份代码),go自然也可以这样子做。

但,我们没有影响力,不像七牛云一样有知名度(他们自己造了一套语法,转译成golang语法),造语法是不可能的:

•IDE 不支持,总不能别人用了这个库,写的代码编译不了,需要调用工具转换后才能跑吧•不可能有人会用的。。

因此,需要暗度陈仓。

先提供interface{}的库函数

golang通过 interface{}可以实现"泛型",但是性能太差,以至于go的作者robpike自己都。。。没眼看。

但没关系,我们可以提供这些函数给用户先使用,在开发,编译,调试都能正常使用,使用如下:

"github.com/PioneerIncubator/betterGo/enum" //引用betterGo的库
func mul(a, b int) (c int) {c = a \* breturn
}
out := enum.Reduce(a, mul, 1).(int)

这些测试例子可在项目的test目录中找到。

转译

之后只需要调用一下我们的工具,转换成具体类型的函数即可,自然,我们也会将调用方的函数改变:

 out := enum.ReduceAMulInt(a, mul, 1) //这时的enum包就是用户项目自己目录里的包了

生成的Reduce函数如下,会在调用方的目录utils/enum/reduce.go里:

package enumfunc ReduceAMulInt(argname\_1 int, argname\_2 func(int, int) int, argname\_3 int) int {lenSlice := len(argname\_1)switch lenSlice {case 0:return 0case 1:return argname\_1\[1\]}out := argname\_2(argname\_3, argname\_1\[0\])next := argname\_1\[1\]for i := 1; i < lenSlice; i++ {next = argname\_1\[i\]out = argname\_2(out, next)}return out
}

编译

这时编译就是特例化版本函数的二进制了。

至于生成的代码,可以git checkout .全部扔掉,开发依然使用interface{}版本的代码。

后记

虽然go2 泛型明年就要出了,但也很悬- -,有兴趣可以参与开发这个项目哈,玩玩也行。点击原文到项目链接

支持的函数


•find(slice, default \ nil, fun)

•Returns the first element for which fun returns a truthy value. If no such element is found, returns default.

•map(slice, fun)

•Returns a list where each element is the result of invoking fun on each corresponding element of enumerable.

•all?(slice, fun \ fn x -> x end)

•Returns true if fun.(element) is truthy for all elements in enumerable.

•any?(slice, fun \ fn x -> x end)

•Returns true if fun.(element) is truthy for at least one element in enumerable.

•uniq_by(slice, fun)

•Enumerates the enumerable, by removing the elements for which function fun returned duplicate elements.


项目细节:

betterGo实现了我认为Go所缺失的部分

Real Generic

为用户提供了可以直接用在代码中的真正的interface{}

在部署之前,仅需要使用translator生成确定类型的代码,这种方式并不会影响你的代码性能。

下面是已经实现的所有泛型函数:

enum.Reduceenum.Map

实现

使用Go AST来分析你使用泛型函数的代码,生成确定类型的函数并替换掉你原先的调用语句

实际上所做的事

背景

现在的Go语言不支持泛型(像C++中的template、Java中的interface)

目前,为实现泛型的需求,在Go语言中往往有如下几种方式1[1]:

1.Interface (with method) 优点:无需三方库,代码干净而且通用。缺点:需要一些额外的代码量,以及也许没那么夸张的运行时开销。2.Use type assertions 优点:无需三方库,代码干净。缺点:需要执行类型断言,接口转换的运行时开销,没有编译时类型检查。3.Reflection 优点:干净 缺点:相当大的运行时开销,没有编译时类型检查。4.Code generation 优点:非常干净的代码(取决工具),编译时类型检查(有些工具甚至允许编写针对通用代码模板的测试),没有运行时开销。缺点:构建需要第三方工具,如果一个模板为不同的目标类型多次实例化,编译后二进制文件较大。

betterGo就是通过code generation来实现泛型

如何使用

如果你想使用betterGo来通过自动生成代码的方式实现泛型,可以看下面的例子:

在项目中包含了测试用例,例如,需要使用泛型的代码是test/map/map.go,如果想用interface{} 的函数就是enum.Map 这样子用。

如果想生成具体类型的函数,就运行这行命令:go run main.go -w -f test/map/map.go

然后你发现 test/map/map.go 改变了,enum.Map 变成了: enum.MapOriginFn(origin, fn)

然后你看项目目录下生成了: utils/enum/map.go,就是具体类型的函数

参与项目

如果想和我们一起完成项目的开发,可以直接看代码,找到AST相关的包,尝试理解相关函数的作用,很容易就可以理解这个项目以及代码了。

如果想从理论出发的话,可以简单看看这本书:https://github.com/chai2010/go-ast-book ,其实他也就是把AST包里的代码简单讲讲。

想参与具体开发可以参考项目接下来的TODO List[2]

技术思路

1.导入需要操作的文件/目录

2.通过AST进行语法分析

AST能分析出每条语句的性质,如:

GenDecl (一般声明):包括import、常量声明、变量声明、类型声明•AssignStmt(赋值语句):包括赋值语句和短的变量声明(a := 1)•FuncDecl(函数声明)•TypeAssertExpr(类型断言)•CallExpr(函数调用语句)

当分析到包含变量的值/类型的语句时(AssignStmtFuncDecl)会对变量的值和类型进行记录,并建立二者之间的映射关系,以便于在后续环节中能够通过变量名获取变量的类型

当发现函数调用语句(CallExpr)时,会检查该函数是否为我们提供的函数,如果是,则通过上一步中记录的参数名对应的类型生成专门处理该类型的一份代码,并存储到指定路径下(如果之前已经生成过相同类型的代码则不重复生成)

将原代码中的原来的函数调用语句替换成新的函数调用语句,使其调用上一步中新生成的函数,并更新import的包

这个大学生,抢先go2实现了go的泛型相关推荐

  1. JAVA泛型特例化_这个大学生,抢先go2实现了go的泛型

    betterGo 天下苦golang久矣! 今亡亦死,举大计亦死,等死,死国可乎 背景 然而生活中,接收了没有泛型,似乎也挺美好的样子,直到某一天,你发现你又要对slice进行删除操作了,明明你前几天 ...

  2. Go语言特性记录及与java、python对比之包、变量和函数

    Go 编程语言是一个开源项目,它使程序员更具生产力. Go 语言具有很强的表达能力,它简洁.清晰而高效.得益于其并发机制,用它编写的程序能够非常有效地利用多核与联网的计算机,其新颖的类型系统则使程序结 ...

  3. 廉洁文化 计算机学院,资讯抢先看 | 廉洁文化主题活动优秀作品锦集,请查收~...

    原标题:资讯抢先看 | 廉洁文化主题活动优秀作品锦集,请查收~ 看了就要关注我,喵呜~ 在大家的共同努力下,"清正在德,廉洁在志"校园廉洁文化主题作品征集活动获得圆满成功. 本活动 ...

  4. 论大学生能参加的比赛,看这一篇文章就够了

    文章数据来源于中国高等教育学会 2021全国普通高校大学生竞赛分析报告发布 规则说明及数据说明 榜单一览表 计算机类比赛 NO.1 ACM国际大学生程序设计竞赛 (ACM/ICPC) NO.2 蓝桥杯 ...

  5. 一个大学生从月薪3500到700万和他的情感经历

    本文章是转载的,出处不详. 一个大学生从月薪3500到700万和他的情感经历--看了我挺震撼的,很佩服他的奋斗精神,特别推荐"三无"(无背景,无势力,无家产)的男生/希望靠自己奋斗 ...

  6. 大学生如何奋斗5年从月薪3500到700万

    来上海整整五年了,事业上已有了突飞猛进的飞跃,生活方面有过一段段的辛酸.然而,如今回首看来,这五年来也这是这些苦恼最终成为我前进的机遇,让我拥有了目前还算可以的生活境遇?700万身价,对有些兄弟来说可 ...

  7. 荣耀出鸿蒙,横空出世 揭开鸿蒙真容!荣耀智慧屏抢先体验

    原标题:横空出世 揭开鸿蒙真容!荣耀智慧屏抢先体验 一.前言:并不是电视 这台智慧大屏久等了 想想你有多久没有开过你们家的电视了? 在智能手机还未开始普及之前,我们用手机/固定电话来联络外界,打开电视 ...

  8. 全国大学生电子设计竞赛

    今天给大家介绍一下全国电子设计竞赛 全国电子设计竞赛是什么样的比赛?竞赛水准在哪里?相信大部分同学有这样的疑问.下面我就简要给各位介绍一下电赛. 说到电赛就就不得不说517,有些人会问517是什么?各 ...

  9. 计算机专业中经典书籍(程序猿和大学生必读)

    2楼 : JAVA篇 此篇收录:.<Java 2 核心技术>.2.<Java编程语言>.3.<Effective Java>.4.<Java解惑>.5. ...

最新文章

  1. ORACLE 12C PDB部分功能测试
  2. [转]php与memcached服务器交互的分布式实现源码分析[memcache版]
  3. HTML事件的执行顺序
  4. 「C++: Eigen」学习笔记
  5. 用博客见证自己的成长
  6. pthread_cond_timedwait方法Linux时间编程
  7. HashMap中,比较key是否相等为什么要重写equal() 和hashCode()这两个方法?
  8. 医院门诊管理系统php文献,医院门诊管理系统(源码+系统)
  9. 经典SQL练习题(MySQL版)
  10. 语音合成论文优选:Mixture Density Network for Phone-Level Prosody Modelling in Speech Synthesis
  11. E45: 'readonly' option is set (add ! to override)
  12. 解决百度云下载缓慢问题
  13. 不用手机的群控,什么原理
  14. ubuntu系统上安virtualbox虚拟机装win10一路踩坑
  15. 阿里巴巴大数据学院落地成都,计划5年培养2000名高端专业人才
  16. 入门数学(二)素数,质因数分解
  17. 费率与利率的差别_费率是什么(利率和费率有啥区别?)
  18. 排列组合的简单应用(隔板法)
  19. 0321 复利计算—贷款
  20. 电路串联和并联图解_电路的组成和连接方式-通路、开路、短路,设计串并联电路图详解...

热门文章

  1. linux停止network服务命令是,Linux系统服务启动和停止
  2. 增加spyder模块代码提示功能和spyder 代码自动补齐设置方式
  3. 数据库与缓存一致性解决方案
  4. 华为android9升级名单,华为EMUI9.0流畅度大提升,更新内容和升级名单汇总
  5. win10+php+com组件,分享Win10系统打不开COM组件提示错误代码80040154的解决方法
  6. Springboot 那年我双手插兜,手写一个excel导出
  7. H3C 路由器内网用户通过域名访问内网服务器的配置方法
  8. python运行pyc文件_Python什么情况下会生成pyc文件?
  9. ORA-22992:无法使用从远处表选择LOB定位器
  10. linux 移动剪切命令,Linux移动剪切文件和目录命令-Linux重命名文件和目录命令-Linux mv命令详解-嗨客网...