Go 1.10,在 Go 1.9 发布半年后如期而至。其主要变化在工具链实现、运行时及库上面。一如既往,该版本秉承 Go 1 兼容性准则。以期所有的 Go 程序如之前一样编译及运行。
该版本改进了包构建缓存,增加了成功测试结果缓存,在测试时自动进行校验,且准许使用 cgo 在 Go 及 C 程序间直接传递 string 类型的值。
1 语言方面
语言基准未有大的变化。
阐明了未指定类型的常量移位,编译器已允许诸如 x[1.0 « s](s 是一个无符号整型变量)的索引表达式。
method expression 语法已放宽到允许任何类型表达式作为接收器;如 struct{io.Reader}.Read 是有效的。
2 工具方面
默认情况下,go tool 会在系统临时文件夹下创建文件夹及文件(如 Unix 的$TMPDIR),若设置了新的变量$GOTMPDIR,即会改为在该文件夹下创建。
go build的-asmflags、-gcflags、-gccgoflags、及-ldflags
选项目前默认仅应用于命令行直接列出的包。例如,go build -gcflags=-m mypkg
会在对 mypkg 包而非其依赖构建时给编译器传入-m 标记。新的更通用的方式-asmflags=pattern=flags
仅会将标记应用到匹配了模式的包。例如:go install -ldflags=cmd/gofmt=-X=main.version=1.2.3 cmd/...
会对满足cmd/...
的包安装所有命令,但仅会对 cmd/gofmt 应用-X 选项。更多详情请参阅go help build
。
go build 命令目前维护了一块最近构建包的缓存(不同于包安装路径$GOROOT/pkg或$GOPATH/pkg)。缓存应会对未显式安装包或当在源码的不同副本中切换时(如在同一版本控制系统的不同分支上前后切换)起到加速构建的作用。之前添加-i 标记以加速(诸如go build -i
或go test -i
)的建议已没有必要:有没有-i 都会一样快,更多详情请参阅go help cache
。
go install 命令目前仅安装直接在命令行列出的包与命令。例如go install cmd/gofmt
安装了 gofmt 程序,但没有安装其任何依赖。新的构建缓存使得未来的命令仍可运行的好似安装了依赖一样快。使用新的go install -i
标记可以强制安装依赖。
go build 的诸多实现细节已对这些改进作了支持。一个新的改变是纯二进制包的引用必须在其被引用源码中声明准确的引用块。这样,当使用纯二进制包链接一个程序的时候以让这些引用是可用的。更多详情请查阅go help filetype
。
go test 命令目前会对将要测试的包自动运行 go vet,以在运行测试前识别重要问题。此类问题会造成构建错误及阻止测试执行。使用 go test -vet=off 可以关闭该检测。
go test -coverpkg 标记目前将其参数解释为一个按冒号分割的模式列表以匹配每个测试的依赖,并非作为一个包列表以重新加载。如 go test -coverpkg=all 目前是一个对测试包及其所有依赖开启覆盖率测试的有趣方式。同样,go test -coverprofile 选项目前也支持运行多组测试。
对于超时的错误情形,测试更可能在退出前写入画像。
go test 目前会从给定的二进制执行中将标准错误并入标准输出然后写到 go test 的标准输出中。而之前 go test 仅会在多数时间应用该合并。
目前,当并行测试停顿或继续的时候,go test -v
输出会包括 PAUSE 及 CONT 状态标记行。
新的go test -failfast标
记在测试失败时将不会运行剩余的测试。(注:以并行方式运行的测试在测试运行失败时允许测试执行完成)
最后,新的go test -json
标记通过新的go tool test2json
命令过滤测试输出以生成机器可读的 JSON 格式的测试执行描述。这样会允许在 IDE 及其它工具中创建更多丰富的说明信息。
更多详情请参阅go help test
及test2json 文档。
$ go doc mail.Address
type Address struct {
Name string // Proper name; may be empty.
Address string // user@domain
}
Address represents a single mail address. An address such as "Barry Gibbs
" is represented as Address{Name: "Barry Gibbs", Address:
"bg@example.com"}.
func ParseAddress(address string) (*Address, error)
func ParseAddressList(list string) ([]*Address, error)
func (a *Address) String() string
之前 ParseAddressList 函数仅会在包预览时显示(go doc mail)。
go tool pprof 画像可视化工具已更新至 git 版本 9e20b5b(github.com/google/pprof
),该版本包含一个更新了的 web 接口。
Vet go vet 命令目前在检查包(甚至对使用 cgo 或 vendored 方式引入的包)的时候总是使用完整的最新的类型信息。结果报告应该会更准确一些。注意仅 go vet 有权访问这些信息,应避免使用 go tool vet。(截至 Go 1.9,go vet 已提供类似 go tool vet 所有标记的访问)
Gofmt Go 源码的默认格式化有两处小的细节上的改动。第一个,对于三索引 slice 表达式之前会被格式化为 x[i+1 : j:k],而目前会被使用定长空格格式化为 x[i+1 : j : k]。第二个,写作单行的单个方法接口(有时会在类型断言时使用)将不再格式化为多行。
注意这类针对 gfmt 的小的更新将会不定期进行。一般讲,检查源码的构建系统应匹配指定版本的 gofmt 的输出。
记录于二进制的 DWARF 调试信息有几项改进:常量值目前会被记录;行号信息会更精确,使得源码级调试更好一些;并且目前每个包会呈现其自己的 DWARF 编译单元。
各种构建模式已移植到更多的系统。特别是 c-shared 目前工作在 linux/ppc64le、windows/386,及 windows/amd64 上;pie 目前工作在 darwin/amd64,且同样在所有系统上强制使用外部链接;plugin 目前工作在 linux/ppc64le 及 darwin/amd64 上。
linux/ppc64le 端目前需要对使用 cgo 的任何程序(甚至被标准库使用时)使用外部链接。
3 运行时
嵌套调用 LockOSThread 及 UnlockOSThread 的行为已发生改变。这些函数用来控制是否一个 goroutine 被锁定在一个操作系统线程上,以让该 goroutine 仅在那个线程上运行,且那个线程仅运行该 goroutine。之前在一行调用 LockOSThread 多次相当于调用一次,而仅调用一次 UnlockOSThread 即可解锁线程。现在调用是嵌套的:调用 LockOSThread 多次,须调用 UnlockOSThread 同样次数才能解锁。没有嵌套调用的现有代码仍可正确运行。多数使用这些函数的公开 Go 源码被分入了第二类。
因通常使用 LockOSThread 与 UnlockOSThread 来允许 Go 源码可靠的修改本地线程状态(如 Linux 或 Plan 9 命名空间)。运行时目前认为被锁的线程不适于重用或用来创建新线程。
除非包装器自己出现了错误,堆栈信息不再包含隐式的包装函数(之前被标记为
GOROOT 函数目前实际上是在调用程序编译后,默认使用 GOROOT 或 GOROOT_FINAL。而之前,是在编译调用程序的工具链编译后,使用 GOROOT 或 GOROOT_FINAL。
GOMAXPROCS 设置目前已无上限。(在 Go 1.9,上限为 1024)
4 性能
一如既往,该版本变化较广,较难对性能作精确陈述。因垃圾收集器加速、更好的代码生成及核心库的优化,多数程序应会运行的快一些。
5 垃圾收集器
当垃圾收集器活跃时,多数程序应会感受到更低的分配延迟及总体的性能提升。
6 核心库
标准库的所有改动都比较小,bytes 包及 net/url 包的变化可能需要更新现有的程序。
参考资料