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 更改。go fix 程式是一個簡單的驅動程式,圍繞著稱為“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 程式碼
部落格索引