注:本文已发布超过一年,请注意您所使用工具的相关版本是否适用
最近写API CURD比较多,为了结构清晰,返回值需要统一错误码,所以在一个统一的errcode包中定义错误码常量,以及其错误信息.
如下图所示,由于常量是导出字符 -> golint 检测需要编写注释 -> 注释信息其实就是错误信息,已经在下文的msg map[int]string中定义,如果在写就得写两遍

不写,就满屏波浪线,不能忍!
写了,就得Copy一份,还不利于维护,不能忍!
能不能只写一份注释,剩下的msg通过读取注释信息自动生成,将我们宝(hua)贵(diao)的生命,从这些重复繁杂无意义的劳动中解放出来。
为了实现这个伟大的目标, 需要以下两个关键的数据:
golang在1.4版本中引入了go generate命令,常用于文件生成,例如在 Golang 官方博客[5]中介绍的Stringer可以为枚举自动实现Stringer的方法,从业务代码中解放出来
使用go help generate我们可以查看一下命令的帮助文档
1 | |
解释很长,就不贴上来了,简要的概括一下:
参数说明
go test -run类似)举个栗子
1 | |
go generate会扫描.go源码文件中的注释//go:generate command args..., 并且执行其命令,注意:
command必须是可执行的指令,例如在 PATH 中或者使用绝对路径arg如果带引号会被识别成一个参数, 例如: //go:generate command "x1 x2", 这条语句执行的命令只有一个参数//和go之间没有空格go generate必须手动执行,如果想等着go build, go test, go run 命令执行的时候自动执行,可以洗洗睡了
为了让别人或者是 IDE 识别代码是通过go generate生成的,请在生成的代码中添加注释(一般放在文件开头)
1 | |
举个栗子:
1 | |
go generate在执行的时候会自动注入以下环境变量:
1 | |
源文件: painkiller.go
1 | |
执行命令
1 | |
生成文件: painkiller_stringer.go
1 | |
从上面的 🌰,我们可以发现,在.go源文件中,添加了一行注释go:generate stringer -type=Pill, 执行命令go generate就调用stringer命令在同目录下生成了一个新的_stringer.go的文件
回想一下上文提到的需求,是不是感觉很类似,从 Go 源文件中,生成了一些不想重复写的业务逻辑
回到前面的需求,我们需要从源代码中获取常量和注释之前的关系,这时就需要我们的 🌲AST 隆重登场了。
本文不对 AST 过多介绍,可以阅读参考资料中的 AST 标准库文档[3],Go 的 AST(抽象语法树)[4]
基础的接口类型
1 | |
等会儿可能会用到的ValueSpec
1 | |
在 godoc[3]的 Example 中可以发现有一个CommentMap例子
1 | |
通过parse读取源码创建一个 AST
1 | |
从 AST 中新建一个CommentMap
1 | |
1 | |
1 | |
1 | |
从一个简单的效率需求引申到go generate和ast的使用,顺便阅读了一下ast的源码,花费的时间其实可能是这个工具节约的时间的几倍了,但是收获也是之前没有想到的。
go命令,详细的阅读了go help command的说明之后,发现之前可能连了解都算不上godoc是最好的使用说明,第二好的是它的源代码注:本文已发布超过一年,请注意您所使用工具的相关版本是否适用
最近写API CURD比较多,为了结构清晰,返回值需要统一错误码,所以在一个统一的errcode包中定义错误码常量,以及其错误信息.
如下图所示,由于常量是导出字符 -> golint 检测需要编写注释 -> 注释信息其实就是错误信息,已经在下文的msg map[int]string中定义,如果在写就得写两遍

不写,就满屏波浪线,不能忍!
写了,就得Copy一份,还不利于维护,不能忍!
能不能只写一份注释,剩下的msg通过读取注释信息自动生成,将我们宝(hua)贵(diao)的生命,从这些重复繁杂无意义的劳动中解放出来。
为了实现这个伟大的目标, 需要以下两个关键的数据:
golang在1.4版本中引入了go generate命令,常用于文件生成,例如在 Golang 官方博客[5]中介绍的Stringer可以为枚举自动实现Stringer的方法,从业务代码中解放出来
使用go help generate我们可以查看一下命令的帮助文档
1 | |
解释很长,就不贴上来了,简要的概括一下:
参数说明
go test -run类似)举个栗子
1 | |
go generate会扫描.go源码文件中的注释//go:generate command args..., 并且执行其命令,注意:
command必须是可执行的指令,例如在 PATH 中或者使用绝对路径arg如果带引号会被识别成一个参数, 例如: //go:generate command "x1 x2", 这条语句执行的命令只有一个参数//和go之间没有空格go generate必须手动执行,如果想等着go build, go test, go run 命令执行的时候自动执行,可以洗洗睡了
为了让别人或者是 IDE 识别代码是通过go generate生成的,请在生成的代码中添加注释(一般放在文件开头)
1 | |
举个栗子:
1 | |
go generate在执行的时候会自动注入以下环境变量:
1 | |
源文件: painkiller.go
1 | |
执行命令
1 | |
生成文件: painkiller_stringer.go
1 | |
从上面的 🌰,我们可以发现,在.go源文件中,添加了一行注释go:generate stringer -type=Pill, 执行命令go generate就调用stringer命令在同目录下生成了一个新的_stringer.go的文件
回想一下上文提到的需求,是不是感觉很类似,从 Go 源文件中,生成了一些不想重复写的业务逻辑
回到前面的需求,我们需要从源代码中获取常量和注释之前的关系,这时就需要我们的 🌲AST 隆重登场了。
本文不对 AST 过多介绍,可以阅读参考资料中的 AST 标准库文档[3],Go 的 AST(抽象语法树)[4]
基础的接口类型
1 | |
等会儿可能会用到的ValueSpec
1 | |
在 godoc[3]的 Example 中可以发现有一个CommentMap例子
1 | |
通过parse读取源码创建一个 AST
1 | |
从 AST 中新建一个CommentMap
1 | |
1 | |
1 | |
1 | |
从一个简单的效率需求引申到go generate和ast的使用,顺便阅读了一下ast的源码,花费的时间其实可能是这个工具节约的时间的几倍了,但是收获也是之前没有想到的。
go命令,详细的阅读了go help command的说明之后,发现之前可能连了解都算不上godoc是最好的使用说明,第二好的是它的源代码