go generate介绍
介绍
go generate
命令是go 1.4版本里面新添加的一个命令,当运行go generate时,它将扫描与当前包相关的源代码文件,找出所有包含//go:generate
的特殊注释,提取并执行该特殊注释后面的命令,命令为可执行程序,形同shell下面执行.
有几点需要注意:
- 该特殊注释必须在
.go
源码文件中. - 每个源码文件可以包含多个
generate
特殊注释时. - 显示运行
go generate
命令时,才会执行特殊注释后面的命令. - 命令串行执行的,如果出错,就终止后面的执行.
- 特殊注释必须以
//go:generate
开头,双斜线后面没有空格.
应用
在有些场景下,我们会使用go generate:
- yacc:从 .y 文件生成 .go 文件.
- protobufs:从 protocol buffer 定义文件(.proto)生成 .pb.go 文件.
- Unicode:从 UnicodeData.txt 生成 Unicode 表.
- HTML:将 HTML 文件嵌入到 go 源码 .
- bindata:将形如 JPEG 这样的文件转成 go 代码中的字节数组.
再比如:
string
方法:为类似枚举常量这样的类型生成String()方法.- 宏:为既定的泛型包生成特定的实现,比如用于ints的sort.Ints.
命令
go generate
命令使用格式如下:
go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]
其中:
-run
正则表达式匹配命令行,仅执行匹配的命令-v
输出被处理的包名和源文件名-n
显示不执行命令-x
显示并执行命令
执行go generate
时,有一些环境变量可以使用:
$GOARCH
体系架构 (arm、amd64等待)
$GOOS
OS环境(linux、windows等)
$GOFILE
当前处理中的文件名
$GOLINE
当前命令在文件中的行号
$GOPACKAGE
当前处理文件的包名
$DOLLAR
固定的"$",不清楚用途
假设我们有个main.go文件,内容如下:
package main
import "fmt"
//go:generate echo hello
//go:generate go run main.go
//go:generate echo file=$GOFILE pkg=$GOPACKAGE
func main() {
fmt.Println("main func")
}
执行“go generate”后,输出如下:
$ go generate
hello
main func
file=main.go pkg=main
示例
现在我们来实践一下前面介绍的go generate
String()方法
假设我们有一些代码,里面包含若干定义为Pill的整型常量:
package painkiller
type Pill int
const (
Placebo Pill = iota
Aspirin
Ibuprofen
Paracetamol
Acetaminophen = Paracetamol
)
为了调试的需要,我们会为这些常量定义String()签名方法:
func (p Pill) String() string
一般情况下,我们可能会像下面这样写:
func (p Pill) String() string {
switch p {
case Placebo:
return "Placebo"
case Aspirin:
return "Aspirin"
case Ibuprofen:
return "Ibuprofen"
case Paracetamol: // == Acetaminophen
return "Paracetamol"
}
return fmt.Sprintf("Pill(%d)", p)
}
这里,我们可以用go generate来实现String():
- 首先,我这里创建一个painkiller.go文件,包含如下内容: ```go //go:generate stringer -type=Pill package painkiller
type Pill int
const ( Placebo Pill = iota Aspirin Ibuprofen Paracetamol Acetaminophen = Paracetamol )
在文件的开头包含了一个`//go:generate stringer -type=Pill`特殊注释,其中`stringer`是个生成`String`方法的工具,为了使用`stringer`方法,**在运行`go generate`命令前,我们需要安装`stringer`工具**,命令如下:
`$ go get golang.org/x/tools/cmd/stringer`
- 然后,在painkiller.go所在的目录下面运行`go generate`命令:
`$ go generate`
我们会发现当前目录下面生成一个`pill_string.go`文件,里面实现了我们需要的`String()`方法,文件内容如下:
```go
// Code generated by "stringer -type=Pill"; DO NOT EDIT.
package painkiller
import "fmt"
const _Pill_name = "PlaceboAspirinIbuprofenParacetamol"
var _Pill_index = [...]uint8{0, 7, 14, 23, 34}
func (i Pill) String() string {
if i < 0 || i >= Pill(len(_Pill_index)-1) {
return fmt.Sprintf("Pill(%d)", i)
}
return _Pill_name[_Pill_index[i]:_Pill_index[i+1]]
}