Go 部落格
介紹 Gofix
下一個 Go 版本將在幾個基礎 Go 包中包含重要的 API 更改。實現 HTTP 伺服器處理程式、呼叫 net.Dial
、呼叫 os.Open
或使用 reflect 包的程式碼將無法構建,除非更新以使用新的 API。既然我們的版本更加穩定且不那麼頻繁,這種情況就會變得常見。這些 API 更改中的每一個都發生在不同的每週快照中,並且可能可以單獨處理;然而,總的來說,它們代表了更新現有程式碼所需的大量手動工作。
Gofix 是一個新工具,可以減少更新現有程式碼所需的工作量。它從原始檔中讀取程式,查詢舊 API 的使用,將其重寫為使用當前 API,然後將程式寫回檔案。並非所有 API 更改都保留舊 API 的所有功能,因此 gofix 並非總能完美地完成工作。當 gofix 無法重寫舊 API 的使用時,它會列印警告,提供使用所在的檔名和行號,以便開發人員可以檢查和重寫程式碼。Gofix 負責處理那些簡單、重複、繁瑣的更改,讓開發人員可以專注於那些真正值得關注的部分。
每次我們進行重要的 API 更改時,我們都會向 gofix 中新增程式碼,以儘可能機械地處理轉換。當您更新到新的 Go 版本並且您的程式碼無法構建時,只需在您的源目錄上執行 gofix 即可。
您可以擴充套件 gofix 以支援您自己的 API 更改。gofix 程式是一個簡單的驅動程式,圍繞著稱為 fixes 的外掛執行,每個外掛處理特定的 API 更改。目前,編寫一個新的 fix 需要對 go/ast 語法樹進行一些掃描和重寫,這通常與 API 更改的複雜程度成正比。如果您想探索,netdialFix
、osopenFix
、httpserverFix
和 reflectFix
都是示例,複雜度依次增加。
我們當然也編寫 Go 程式碼,而且我們的程式碼也同樣受到這些 API 更改的影響。通常,我們在進行 API 更改的同時編寫 gofix 支援,然後使用 gofix 重寫主原始碼樹中的用法。我們使用 gofix 更新其他 Go 程式碼庫和我們的個人專案。甚至在需要針對新的 Go 版本進行構建時,我們也會使用 gofix 更新 Google 的內部原始碼樹。
例如,gofix 可以重寫像 這個來自 fmt/print.go
的程式碼片段
switch f := value.(type) {
case *reflect.BoolValue:
p.fmtBool(f.Get(), verb, field)
case *reflect.IntValue:
p.fmtInt64(f.Get(), verb, field)
// ...
case reflect.ArrayOrSliceValue:
// Byte slices are special.
if f.Type().(reflect.ArrayOrSliceType).Elem().Kind() == reflect.Uint8 {
// ...
}
// ...
}
以適應新的 reflect API
switch f := value; f.Kind() {
case reflect.Bool:
p.fmtBool(f.Bool(), verb, field)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p.fmtInt64(f.Int(), verb, field)
// ...
case reflect.Array, reflect.Slice:
// Byte slices are special.
if f.Type().Elem().Kind() == reflect.Uint8 {
// ...
}
// ...
}
上面幾乎每一行都有一些細微的變化。重寫涉及的更改很廣泛,但幾乎完全是機械性的,這正是計算機擅長的事情。
Gofix 之所以成為可能,是因為 Go 在其標準庫中支援將 Go 原始檔解析成語法樹以及將這些語法樹列印回 Go 原始碼。重要的是,Go 列印庫以官方格式(通常透過 gofmt 工具強制執行)列印程式,這使得 gofix 可以在不對 Go 程式造成無關格式更改的情況下進行機械性更改。事實上,建立 gofmt 的關鍵動機之一——或許僅次於避免關於特定大括號位置的爭論——就是為了簡化像 gofix 這樣重寫 Go 程式的工具的建立。
Gofix 已經變得不可或缺。特別是最近的 reflect 更改,如果沒有自動化轉換將是難以接受的,而且 reflect API 也迫切需要重做。Gofix 使我們能夠修正錯誤或徹底重新思考包的 API,而不必擔心轉換現有程式碼的成本。我們希望您會覺得 gofix 像我們一樣有用和方便。
下一篇文章:Go 在 Heroku
上一篇文章:Godoc:記錄 Go 程式碼
部落格索引