Go語言AST嘗試


Go語言有很多工具, goimports用於package的自動導入或者刪除, golint用於檢查源碼中不符合Go coding style的地方, 比如全名,注釋等. 還有其它工具如gorename, guru等工具. 作為工具它們都是使用go語言(查看)開發的, 這些工具都有一個共同點就是: 讀取源代碼, 分析源代碼, 修改或生成新代碼.

 

簡述

很多編程語言/庫/框架等都能生成代碼, 比如使用rails, 可以輕松地new一個project出來, 生成項目基本代碼, 我們稱其為boilerplate, 或者template, 這已經習以為常了. 像ruby的動態語言通常能在運行時生成代碼, 我們稱之為meta programming(元編程), 比如rails的resources可以生成restful的router出來.因為是運行時動態生成, 因此可能會遇到exception, 以及性能方面有所損失.

像elixir這種編程語言的macro則比ruby的元編程方面向"前"一步, 它在編譯期生成代碼, 而不在運行時生成, 好處是可以生成大量的代碼而對性能幾乎沒有太大影響. 像phoenix框架的router查看部分, 則通過macro生成大量的函數, 利用BEAM的pattern matching機制高效路由.elixir的macro是寫在源代碼里的, 而Go則可以分離.

Go語言可以通過reflect包同樣做到ruby的運行時生成代碼(比如創建對象), 但更強大的一點是, 它通過讀取源碼, 再修改源碼, 生成新的代碼.我們可以將這個過程單獨寫作一個工具, 這個工具可以適用於不同的項目.

 

例子

stringer

package game

//go:generate stringer -type=GameStatus
// 注意//與go:generate字符之間不能有空格
// GameStatus 表示比賽的狀態
type GameStatus int

const (
	Unvalid GameStatus = iota
	ValidFailed
	Valid
	Register
	Start
	Running
	End
)

運行 go generate 會生成gamestatus_string.go文件, 並且實現了Stringer接口.

同樣的例子在gRPC中也出現過code, 生成的string.正如Rob Pike所說:

let the mechine do the work.source

 

gen_columns

很多項目在使用數據庫時, 通過tag指定數據庫里的字段名字, 在寫SQL時, 又只能通過字符串來表示字段名, 因此如果某一個字段名修改時, 則意味着涉及到此字段的SQL都面臨着修改, 而我們希望只需要修改一個地方.

有一個結構作為數據庫表結構如下:

type User struct {
    ID int `json:"id" bson:"id"`
    Name string `json:"name" bson:"name"`
}

當使用這個model里的字段進行sql查詢時, 通常使用:

map[string]interface{}{
    "id":123456,
}

作為查詢條件, 如果當字段名更改時, 不得不修改這個map里的key值
如果能夠自動生成一個結構體, 用於表示這些column name值, 那么只需修改一處:

map[string]interface{}{
    UserColumns.ID: 123456
}

 

使用方法

gen_columns -tag="bson" -path="./models/user.go"

會生成一個獨立的文件, 里面的內容為:

package models

type _UserColumn struct {
	ID   string
	Name string
}

var UserColumns _UserColumn

func init() {
	UserColumns.ID = "id"
	UserColumns.Name = "name"

}

 

總結
gen_columns是自己在項目中遇到問題所給出的解決辦法, 第一版本是通過reflect做的, 總共需要好幾個步驟; 使用ast做就只需在編譯時多加一個go generate, 而這命令基本上可以集成在build的腳本里, 因此不需要再額外擔心代碼生成的問題.
讓我們用Go創造更多生成代碼的工具吧.

  

其它例子 

  • impl 指定一個接口, 生成接口所需方法
  • goa 一套用於寫web service的DSL


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM