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 代码
博客索引