对于一个不稳定的语言,删删改改什么的都是常事。即便是稳定的语言,也逃不过隔三差五整修一下的命运。于是 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 变更程度成正比。如果想要了解,netdialFix、osopenFix、 httpserverFix 和reflectFix 是说明示例,从易到难的顺序。
当然,同样也是 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
Leave a comment