Gofix介绍

本文翻译自《Introducing Gofix》。

Russ Cox

2011/04/15

下一个Go版本将在几个基本Go包中进行API的重大更改。实现HTTP服务器处理程序调用net.Dial调用os.Open使用反射包的代码将不会生成成功,除非将其更新为使用新的API。现在我们的版本更加稳定,频率也降低了,这将是一种常见情况。每一个API更改都发生在不同的每周快照中,并且可能由它们的开发者自己单独管理;然而,这些更改加在一起,更新现有代码时就需要大量的手动工作。

Gofix是一种新工具,它减少了更新现有代码所需的工作量。它从源代码文件中读取程序代码,查找使用旧API的地方,将其重写为使用当前API,然后将程序代码写回源代码文件。并非所有API更改都保留了旧API的所有功能,因此gofix无法始终做到完美。当gofix无法重写使用旧API的代码时,它会打印一条警告,给出源代码文件名和行号,以便开发人员检查和重写相关代码。Gofix负责处理简单、重复、乏味的更改,这样开发人员就可以专注于真正值得关注的更改。

每次我们对API进行重大更改时,我们都会在gofix中添加代码,以尽可能机械地处理代码转换。当你更新到新的Go版本并且你的代码不再能构建成功时,只需在源代码目录上运行gofix即可。

你可以扩展gofix以支持对自己的API进行更改。gofix是一个简单的由插件驱动的程序,插件系统叫作fixes,其中每个插件(一个fix)处理一个特定的API更改。现在,编写一个新的修复程序需要对go/ast语法树进行一些扫描和重写,通常与API更改的复杂程度成比例。如果你想探索一下,netdialFixosopenFixhttpserverFixreflectFix都是说明性的例子,它们的复杂度依次增高。

当然,我们自己也编写Go代码,我们的代码和你的代码一样受到这些API更改的影响。通常,我们在更改API的同时编写gofix支持,然后使用gofix重写主(main)源代码树分支中的用法。我们使用gofix来更新其他Go代码库和我们的个人项目。当需要针对新的Go版本进行构建时,我们甚至会使用gofix来更新谷歌内部的源代码树。

例如,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 {
        // ...
    }
// ...
}

为使用新的反射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打印库(printer)以官方推荐的格式打印程序源码(通常通过gofmt工具强制执行),允许gofix对Go程序进行机械地更改,而不会导错误的格式更改。事实上,创建gofmt的一个关键动机可能仅次于避免关于括号应该放在何处的争论,那就是让重写Go程序源码的工具变得简单,无论是创建还是使用,例如gofix。

Gofix已经变得不可或缺。特别是,如果没有自动转换,最近对反射API的更改将是不受欢迎的,并且难以修改之前程序源码里的反射API。Gofix使我们能够修复错误或完全重新思考API,而无需担心转换现有代码所需的成本。我们希望你能发现gofix这个工具是有用和方便的。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注