介紹
go generate命令是go 1.4版本里面新添加的一個(gè)命令遏暴,當(dāng)運(yùn)行g(shù)o generate時(shí),它將掃描與當(dāng)前包相關(guān)的源代碼文件,找出所有包含"http://go:generate"的特殊注釋?zhuān)崛〔?zhí)行該特殊注釋后面的命令粤咪,命令為可執(zhí)行程序,形同shell下面執(zhí)行饰恕。
有幾點(diǎn)需要注意:
- 該特殊注釋必須在.go源碼文件中。
- 每個(gè)源碼文件可以包含多個(gè)generate特殊注釋時(shí)井仰。
- 顯示運(yùn)行g(shù)o generate命令時(shí)埋嵌,才會(huì)執(zhí)行特殊注釋后面的命令。
- 命令串行執(zhí)行的糕档,如果出錯(cuò)莉恼,就終止后面的執(zhí)行。
- 特殊注釋必須以"http://go:generate"開(kāi)頭速那,雙斜線(xiàn)后面沒(méi)有空格俐银。
應(yīng)用
在有些場(chǎng)景下,我們會(huì)使用go generate:
- yacc:從 .y 文件生成 .go 文件端仰。
- protobufs:從 protocol buffer 定義文件(.proto)生成 .pb.go 文件捶惜。
- Unicode:從 UnicodeData.txt 生成 Unicode 表。
- HTML:將 HTML 文件嵌入到 go 源碼 荔烧。
- bindata:將形如 JPEG 這樣的文件轉(zhuǎn)成 go 代碼中的字節(jié)數(shù)組吱七。
再比如:
- string方法:為類(lèi)似枚舉常量這樣的類(lèi)型生成String()方法。
- 宏:為既定的泛型包生成特定的實(shí)現(xiàn)鹤竭,比如用于ints的sort.Ints踊餐。
命令
go generate命令使用格式如下:
go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]
其中:
- -run 正則表達(dá)式匹配命令行,僅執(zhí)行匹配的命令
- -v 輸出被處理的包名和源文件名
- -n 顯示不執(zhí)行命令
- -x 顯示并執(zhí)行命令
執(zhí)行g(shù)o generate時(shí)臀稚,有一些環(huán)境變量可以使用:
$GOARCH
體系架構(gòu) (arm吝岭、amd64等待)
$GOOS
OS環(huán)境(linux、windows等)
$GOFILE
當(dāng)前處理中的文件名
$GOLINE
當(dāng)前命令在文件中的行號(hào)
$GOPACKAGE
當(dāng)前處理文件的包名
$DOLLAR
固定的"$",不清楚用途
假設(shè)我們有個(gè)main.go文件,內(nèi)容如下:
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")
}
執(zhí)行“go generate”后窜管,輸出如下:
$ go generate
hello
main func
file=main.go pkg=main
示例
現(xiàn)在我們來(lái)實(shí)踐一下前面介紹的go generate散劫。
String()方法
假設(shè)我們有一些代碼,里面包含若干定義為Pill的整型常量:
package painkiller
type Pill int
const (
Placebo Pill = iota
Aspirin
Ibuprofen
Paracetamol
Acetaminophen = Paracetamol
)
為了調(diào)試的需要幕帆,我們會(huì)為這些常量定義String()簽名方法:
func (p Pill) String() string
一般情況下获搏,我們可能會(huì)像下面這樣寫(xiě):
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來(lái)實(shí)現(xiàn)String():
- 首先失乾,我這里創(chuàng)建一個(gè)painkiller.go文件常熙,包含如下內(nèi)容:
//go:generate stringer -type=Pill
package painkiller
type Pill int
const (
Placebo Pill = iota
Aspirin
Ibuprofen
Paracetamol
Acetaminophen = Paracetamol
)
在文件的開(kāi)頭包含了一個(gè)"http://go:generate stringer -type=Pill"特殊注釋?zhuān)渲衧tringer是個(gè)生成String方法的工具,為了使用stringer方法碱茁,在運(yùn)行"go generate"命令前症概,我們需要安裝stringer工具,命令如下:
$ go get golang.org/x/tools/cmd/stringer
- 然后早芭,在painkiller.go所在的目錄下面運(yùn)行"go generate"命令:
$ go generate
我們會(huì)發(fā)現(xiàn)當(dāng)前目錄下面生成一個(gè)pill_string.go文件,里面實(shí)現(xiàn)了我們需要的String()方法诅蝶,文件內(nèi)容如下:
// 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]]
}
參考
[1]. Go學(xué)習(xí)筆記 附錄
[2]. Generating code
[3]. Go generate: A Proposal
[4]. Generate Go files by processing source