$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进行编译
/ BPF_CFLAGS are set by the Makefile. //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc 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)


**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://gitee.com/vip204888)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**