【翻译】gofix 介绍

对于一个不稳定的语言,删删改改什么的都是常事。即便是稳定的语言,也逃不过隔三差五整修一下的命运。于是 Golang 大修是个麻烦。
用 Golang 的好处是你正在使用世界上最聪明的一群科学家和工程师的杰作。于是,升级这些麻烦事变得不那么麻烦了,因为有了 gofix。

原文在此:http://blog.golang.org/2011/04/introducing-gofix.html
——————————-翻译分割线——————————-

gofix介绍

下一个 Go 的发布版将会包含多个官方 Go 包 API 的重大变化。实现 HTTP 服务器处理调用 net.Dial调用 os.Open,或者使用反射的代码如果不使用新的 API 升级,将无法编译。现在的发布已经相当稳定并且不那么频繁了,这将会成为一个常态。每次的 API 变化发生在每周的快照版本之间,并且可控;总之,无论如何,这带来了大量需要手工更新的已有代码。

gofix 是一个减少了大量升级已有代码工作的新工具。它从源代码中读取程序,寻找旧的 API,用当前 API 改写它们,然后将程序写回文件。并不是所有的 API 变化都保存了下来,所以 gofix 并不是总能良好的工作。当 gofix 不能改写旧的 API,它打印一条警告,给出文件名和行号,这样开发者可以检查并改写代码。gofix 处理那些简单的、重复的、冗长的修改,这样开发者可以集中精力对付那些真正值得注意的东西。

每次 API 发生了重大变化,都会添加代码到 gofix 来尽可能的处理转换。当升级到新的 Go 发布版本,而已有代码无法编译,只要在代码目录上执行 gofix。

也可以扩展 gofix 以支持自有 API 的改动。gofix 程序是一个简单的驱动调用修复扩展,每个扩展都处理一个特定的 API 变更。现在,编写新的修复需要扫描和改写 go/ast 语法树,通常复杂程度跟 API 变更程度成正比。如果想要了解,netdialFixosopenFixhttpserverFixreflectFix 是说明示例,从易到难的顺序。

当然,同样也是 Go 代码,我们的代码跟你的一样受到这些 API 变化的影响。通常,我们在 API 变化的同时编写 gofix 支持,然后用 gofix 改写主代码树中使用到的地方。我们在其他 Go 代码和个人项目中使用 gofix 进行升级。我们甚至使用 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 {
        // ...
    }   
// ...
}

使其能够配合新的反射 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 的动机之一(可能另一个是避免争论大括号应该在哪)是建立一个能够更加容易重写 Go 程序的工具,就像 gofix 做的那样。

gofix 已经让它变得不可或缺。特别是近期反射的修改,在没有自动化转换的情况下可能相当令人不快,而反射 API 极为需要重新处理。gofix 提供了修复错误或者完全重构包的 API 的能力,而无须担心现有代码转换的问题。我们希望你能像我们一样,发现 gofix 是一个有用并且方便的工具。

– Russ Cox,四月 2011

Join the Conversation

2 Comments

Leave a comment

Your email address will not be published. Required fields are marked *