代码生成利器 - Go Generate,让人茅塞顿开

50 阅读3分钟

$go generate main.go top middle tail


### 正则匹配生成


go generate还可以通过-run使用正则式去匹配各源文件中go generate指示符中的命令,并仅执行匹配成功的命令:



// 未匹配到任何go generate指示符中的命令 $go generate -x -v -run "protoc" ./... main.go subpkg1/subpkg1.go subpkg2/subpkg2.go


### Generate应用场景



#### 生成枚举类型的String方法


这里我们需要安装stringer工具



go install golang.org/x/tools/cmd/stringer@latest


假如有如下枚举



type BACnetComfirmedServiceChoice byte

const ( ServiceConfirmedAcknowledgeAlarm BACnetComfirmedServiceChoice = 0 //确认报警服务 ServiceConfirmedComfirmedCOVNotification BACnetComfirmedServiceChoice = 1 //证实COV通告服务 ServiceConfirmedComfirmedEventNotification BACnetComfirmedServiceChoice = 2 //证实事件通过服务 }


通常我们会为枚举类型手写String方法,这样在打印上面枚举常量时能输出有意义的内容:



func (d BACnetComfirmedServiceChoice ) String() string { switch d { case ServiceConfirmedAcknowledgeAlarm : return "确认报警服务" case ServiceConfirmedComfirmedCOVNotification : return "证实COV通告服务" case ServiceConfirmedComfirmedEventNotification: return "证实事件通过服务" }

return "确认报警服务"

}


如果一个项目中枚举常量类型有很多,逐个为其手写String方法费时费力。当枚举常量有变化的时候,手动维护String方法十分烦琐且易错。对于这种情况,使用go generate驱动stringer工具为这些枚举类型自动生成String方法的实现不失为一个较为理想的方案。下面就是利用go generate对上面示例的改造:



//go:generate stringer -type=BACnetComfirmedServiceChoice -linecomment type BACnetComfirmedServiceChoice byte

const ( ServiceConfirmedAcknowledgeAlarm BACnetComfirmedServiceChoice = 0 //确认报警服务 ServiceConfirmedComfirmedCOVNotification BACnetComfirmedServiceChoice = 1 //证实COV通告服务 ServiceConfirmedComfirmedEventNotification BACnetComfirmedServiceChoice = 2 //证实事件通过服务 }


利用generate生成代码如下:



// Code generated by "stringer -type=BACnetComfirmedServiceChoice -linecomment"; DO NOT EDIT.

package generate

import "strconv"

func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. var x [1]struct{} _ = x[ServiceConfirmedAcknowledgeAlarm-0] _ = x[ServiceConfirmedComfirmedCOVNotification-1] _ = x[ServiceConfirmedComfirmedEventNotification-2] }

const _BACnetComfirmedServiceChoice_name = "确认报警服务证实COV通告服务证实事件通过服务"

var _BACnetComfirmedServiceChoice_index = [...]uint8{0, 18, 39, 63}

func (i BACnetComfirmedServiceChoice) String() string { if i >= BACnetComfirmedServiceChoice(len(_BACnetComfirmedServiceChoice_index)-1) { return "BACnetComfirmedServiceChoice(" + strconv.FormatInt(int64(i), 10) + ")" } return _BACnetComfirmedServiceChoice_name[_BACnetComfirmedServiceChoice_index[i]:_BACnetComfirmedServiceChoice_index[i+1]] }


#### protobuf


通过generate将protoc预生成指令写在代码中



package main

import ( "fmt" msg "go-generate/protobuf/msg" )

//go:generate protoc -I ./IDL msg.proto --gofast_out=./msg func main() { var m = msg.Request{ MsgID: "xxxx", Field1: "field1", Field2: []string{"field2-1", "field2-2"}, } fmt.Println(m) }


#### ebpf


在cilium/ebpf中使用generate调用其cmd下的bpf2go进行编译



/ BPFCLANGandBPF_CLANG and BPF_CFLAGS are set by the Makefile. //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc BPFCLANGcflagsBPF_CLANG -cflags BPF_CFLAGS bpf xdp.c -- -I../headers

func main() { .... }


### 总结`go generate`​ 命令是一个非常有用的工具,它可以帮助我们自动化地生成代码。在本文中,我们介绍了如何在Go源代码中使用 `go generate`​ 命令,并提供了一些示例来说明它的用法。使用 `go generate`​ 命令可以提高我们的开发效率,减少我们的重复性工作。


‍


## 参考资料


1. [命令 go - Go 编程语言 (google.cn)](https://gitee.com/vip204888)
2. [Generating code - The Go Programming Language](https://gitee.com/vip204888)
3. [gostringer 命令 - github.com/sourcegraph/gostringer - go 包](https://gitee.com/vip204888)
4. [ebpf/main.go at master · cilium/ebpf (github.com)](https://gitee.com/vip204888)


推荐一个零声学院免费教程,个人觉得老师讲得不错,分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,  
 fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,  
 TCP/IP,协程,DPDK等技术内容,点击立即学习](https://gitee.com/vip204888)





![img](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/38fae068a2c84e7ebd3d2512ec8aa6c0~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5py65Zmo5a2m5Lmg5LmL5b-DQUk=:q75.awebp?rk3s=f64ab15b&x-expires=1771857422&x-signature=AbMDZWs9k%2Bm46T1X%2FlAbLWk%2FghY%3D)
![img](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/559dfacfbf2549ea9fb3cff18ef3fa1a~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5py65Zmo5a2m5Lmg5LmL5b-DQUk=:q75.awebp?rk3s=f64ab15b&x-expires=1771857422&x-signature=qYusnzSHqxxlwdAMlsUtp%2FnBmNk%3D)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://gitee.com/vip204888)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**