推進需求
GO 項目,可整體生成一個運行文件到處跑,是極爽之事。但如果有資源文件要得帶着跑,則破壞了這種體驗。
例如下邊這個項目結構,resource 目錄下為資源文件,main.go 中會通過路徑引用到這些資源文件,於是新的需求產生了。
|- hello
----|- resource
---------|- note.txt
----|- main.go
需求推進一步:將資源文件打包至運行文件中,在代碼中仍然使用類似相對路徑的引用方式使用它(這個很重要,使用在概念上保持一致)。
解決方案跟上:把資源文件數據轉換成 GO 代碼中的變量值存儲,並提供函數可根據路徑差數返回相應的數據。這樣一來資源文件就變成了代碼文件,又可以一個運行文件到處跑了。
工具跟進 go-bindata
於是,工具 go-bindata 就來了,它來完成將資源文件變成 GO 代碼的工作。
go get -u github.com/jteeuwen/go-bindata/...
go install
在 hello 項目目錄下執行這個工具,就會生成 -o 指定的 bindata.go 代碼文件。
go-bindata -pkg main -o bindata.go resource/
此時,在 hello 目錄下就多了 bindata.go 代碼文件,然后,在 main.go 中,就可以使用以下方式指定相對路徑參數來取得資源數據。
bs, _ := Asset("resource/note.txt")
生成代碼機制 go generate
有了上述工具,當 note.txt 數據有更新時,就需要使用 go-bindata 工具重新生成代碼文件再編譯,可不可以形成一種專門的機制來規范化這類動作呢?
於是,再進一步,若能如此甚好:
(1)GO 項目的代碼中,能自描述的表明有些相關依賴代碼由需要由工具產生。
(2)支持簡單的方式來完成自描述所表明的操作動作。
於是,go generate 應運而生,來看一下它的大概描述。
go generate 命令是 go 1.4 版新添加的一個命令,它將掃描與當前包相關的源代碼文件,找出所有包含 "//go:generate" 的特殊注釋,提取並執行該特殊注釋后面的命令,命令為可執行程序。
是不是完美的實現了上述兩項訴求。
(1)在源代碼,即 GO 文件中,進行注釋(自描述)即可指定要執行的工具命令。
除了 go-bindata 工具之外,類似的工具定是還有很多。工具抽象出來可認為就是可執行命令,指定命令甚是靈活。
(2)只要執行一條命令,即可自動掃描當前包相關的源代碼文件來完成相應的執行。
這說明,不論有多少個這樣的命令需要執行,它會負責找到並執行。
小小實例,一目了然
開頭項目結構中,main.go 的完整代碼如下:
//go:generate go-bindata -pkg main -o bindata.go resource/
//go:generate go build
//go:generate hello
package main
import (
"fmt"
)
func main() {
bs, _ := Asset("resource/note.txt")
fmt.Println(string(bs))
}
注釋部分即描述了三個動作,完成資源文件代碼生成,編譯與運行命令,當執行 go generate 時,三條命令執行下來運行的結果為顯示 note.txt 中的文本內容。運行效果如下,當修改了 note.txt,執行 go generate,會自動完成重新生成代碼,編譯和運行。