大家好,我是猫头虎,今天我们来探讨Go 1.4版本中引入的一个强大的新功能——代码生成。这个功能不仅展示了通用计算的强大之处,也为Go语言的软件工程实践带来了全新的可能性。让我们一起深入了解代码生成的魔力吧!
通用计算的一个重要属性——图灵完备性——意味着计算机程序可以编写计算机程序。这是一个强大的概念,但却没有得到应有的重视。现在,随着Go 1.4的发布,我们得以在Go语言中更方便地实现这一点。
代码生成指的是一个程序输出另一个程序的源代码。这是软件工程中的一个重要元素,常见于编译器的定义中。例如,go test
命令就是通过扫描要测试的包,写出为该包定制的测试装置的Go程序,然后编译并运行它。
go generate
Go 1.4引入了一个新命令go generate
,通过扫描Go源代码中的特殊注释来识别并运行通用命令。值得注意的是,go generate
并不是go build
的一部分。它没有依赖分析,并且在运行go build
之前必须显式运行。它旨在被Go包的作者使用,而不是其客户端。
go generate
例如,使用Go的Yacc工具生成Yacc语法:
安装Go的Yacc工具:
go get golang.org/x/tools/cmd/goyacc
假设有一个名为gopher.y
的Yacc输入文件,定义了新语言的语法。要生成实现该语法的Go源文件,通常会这样调用命令:
goyacc -o gopher.go -p parser gopher.y
要使用go generate
来驱动这个过程,在同一目录下的任何一个常规(非生成的).go
文件中,添加以下注释:
//go:generate goyacc -o gopher.go -p parser gopher.y
运行go generate
,然后构建和测试:
$ cd $GOPATH/myrepo/gopher
$ go generate
$ go build
$ go test
stringer
工具stringer
是golang.org/x/tools
仓库中的一个新程序,它自动为整数常量集编写字符串方法。虽然可以单独运行,但它主要是由go generate
驱动的。
设想我们有一些代码,包含定义不同类型药丸的整数常量集:
package painkiller
type Pill int
const (
Placebo Pill = iota
Aspirin
Ibuprofen
Paracetamol
Acetaminophen = Paracetamol
)
使用stringer
,只需添加一个生成注释,即可让go generate
为Pill
类型生成String
方法。输出默认写入pill_string.go
。
Go
语言中已经有许多其他使用go generate
的实例,包括在unicode
包中生成Unicode表、在encoding/gob
中创建数组的编码和解码方法等。
go generate
虽然没有提供Make或其他构建机制无法做到的功能,但它无需额外安装即与go
工具一起提供,并且很好地融入了Go生态系统。请创造性地使用go generate
,它鼓励实验。本文已被猫头虎的Go生态洞察专栏收录,详情点击这里。