代码分享 等不及 go 泛型发布,我先实现了(类似 C++ 的 template)

shanjin · 2020年06月17日 · 最后由 sotex 回复于 2020年09月02日 · 3667 次阅读
本帖已被设为精华帖!

https://github.com/PioneerIncubator/betterGo 这个项目就是我带着一位师弟实现的,有兴趣的同学一起开发哈~

betterGo

Better Go implement parts that I think Golang missed

Real Generic

Provide the real interface{} to you so that you can use it in your code. Before deployment, just use translator to generate specify type code, in which way will not affect your performance.

Here are all generic functions:

  • enum.Reduce
  • enum.Map

Implementation

Use go ast to analyse your code where using generic functions, generate specify function for your types and replace your original call.

What I actually do

I do this shit for you :P

betterGo

Join Us

wechat group

Background

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

目前,为实现泛型的需求,在 Go 语言中往往有如下几种方式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 包里的代码简单讲讲。

想参与具体开发的话,又没有想改进的地方,可以看看 issue 列表哈:https://github.com/PioneerIncubator/betterGo/issues

技术思路

  1. 导入需要操作的文件,可以是文件/目录

  2. 通过 AST 进行语法分析

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

  • GenDecl (一般声明):包括 import、常量声明、变量声明、类型声明
  • AssignStmt(赋值语句):包括赋值语句和短的变量声明 (a := 1)
  • FuncDecl(函数声明)
  • TypeAssertExpr(类型断言)
  • CallExpr(函数调用语句)
  1. 当分析到包含变量的值/类型的语句时 (AssignStmtFuncDecl) 会对变量的值和类型进行记录,并建立二者之间的映射关系,以便于在后续环节中能够通过变量名获取变量的类型

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

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

Reference

- [1] Go 有什麽泛型的实现方法? - 达的回答 - 知乎
更多原创文章干货分享,请关注公众号
  • 加微信实战群请加微信(注明:实战群):gocnio

有点意思了. 感谢分享.

顶!山老师,永远滴神!

tsingson 回复

哈哈,有兴趣可以一起开发

astaxie 将本帖设为了精华贴 06月18日 14:29
Orichalcum GoCN 每日新闻 (2020-06-18) 中提及了此贴 06月18日 14:50
astaxie 回复

哈哈,谢谢 beego 作者

有意思,类似于代码生成器?

对,是这样子

这和 genny 有啥区别

我刚开始写 Go 就是这样写的,当时戏称为:"手动泛型"

cch123 回复

还是不一样,虽然都是 code generation,但是 genny 是提供泛型方法给用户用; 我们是提供泛型库给他们用

我就是那个把 ast 包里的代码简单讲讲的《Go 语法树入门——开启自制编程语言和编译器之旅》作者。

其实作者这类工作都是基于 ast 做再处理,gofmt 和 golint 检查也是基于 ast 做分析。 甚至基于 ast 可以扩展出新的语法来,比如七牛面向数据科学语言的 Go+ 语言。

当然,为了写这个书,我们也定制了一个凹语言:目前已经是一个可以嵌入 Go 语言的脚本语言, 也是基于 Go 语言的 ast 定制,在凹语言的基本功能完成之后我们会公开代码 (http://github.com/wa-lang)。

欢迎关注 https://github.com/chai2010/go-ast-book

抱歉。。没想到圈子这么小- = -,下次还是要注意不要暴言😂 书写很好,我的意思是对我这个项目来说,就帮助没有很大,因为项目太简单了

大佬也在这里啊。大佬给开源界贡献了很多作品啊👍

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册