网页
综合
更新时间 2026-11-14 09:29:23
Backward Compatibility, Go 1.21, and Go 2 - The Go Programming Language
自动蜘蛛
go.dev
正文约 5999 字
Common problems companies solve with Go
Stories about how and why companies use Go
How Go can help keep you secure by default
The official Go language specification
A complete introduction to building software with Go
Reference documentation for Go's standard library
Learn what's new in each Go release
Tips for writing clear, performant, and idiomatic Go code
Videos from prior events
Meet other local Go developers
Learn and network with Go developers from around the world
The Go project's official blog.
Get help and stay informed from Go
Russ Cox 14 August 2023
Go 1.21 includes new features to improve compatibility. Before you stop reading, I know that sounds boring. But boring can be good. Back in the early days of Go 1, Go was exciting and full of surprises. Each week we cut a new snapshot release and everyone got to roll the dice to see what we’d changed and how their programs would break. We released Go 1 and its compatibility promise to remove the excitement, so that new releases of Go would be boring.
Boring is good. Boring is stable. Boring means being able to focus on your work, not on what’s different about Go. This post is about the important work we shipped in Go 1.21 to keep Go boring.
We’ve been focused on compatibility for over a decade. For Go 1, back in 2012, we published a document titled “Go 1 and the Future of Go Programs” that lays out a very clear intention:
It is intended that programs written to the Go 1 specification will continue to compile and run correctly, unchanged, over the lifetime of that specification. … Go programs that work today should continue to work even as future releases of Go 1 arise.
There are a few qualifications to that. First, compatibility means source compatibility. When you update to a new version of Go, you do have to recompile your code. Second, we can add new APIs, but not in a way that breaks existing code.
The end of the document warns, “[It] is impossible to guarantee that no future change will break any program.” Then it lays out a number of reasons why programs might still break.
For example, it makes sense that if your program depends on a buggy behavior and we fix the bug, your program will break. But we try very hard to break as little as possible and keep Go boring. There are two main approaches we’ve used so far: API checking and testing.
Perhaps the clearest fact about compatibility is that we can’t take away API, or else programs using it will break.
For example, here’s a program someone has written that we can’t break:
We can’t remove the package os; we can’t remove the global variable os.Stdout, which is an *os.File; and we also can’t remove the os.File method WriteString. It should be clear that removing any of those would break this program.
It’s perhaps less clear that we can’t change the type of os.Stdout at all. Suppose we want to make it an interface with the same methods. The program we just saw wouldn’t break, but this one would:
This program passes os.Stdout to a function named greet that requires an argument of type *os.File. So changing os.Stdout to an interface will break this program.
To help us as we develop Go, we use a tool that maintains a list of each package’s exported API in files separate from the actual packages:
One of our standard tests checks that the actual package APIs match those files. If we add new API to a package, the test breaks unless we add it to the API files. And if we change or remove API, the test breaks too. This helps us avoid mistakes. However, a tool like this only finds a certain class of problems, namely API changes and removals. There are other ways to make incompatible changes to Go.
That leads us to the second approach we use to keep Go boring: testing.
The most effective way to find unexpected incompatibilities is to run existing tests against the development version of the next Go release. We test the development version of Go against all of Google’s internal Go code on a rolling basis. When tests are passing, we install that commit as Google’s production Go toolchain.
If a change breaks tests inside Google, we assume it will also break tests outside Google, and we look for ways to reduce the impact. Most of the time, we roll back the change entirely or find a way to rewrite it so that it doesn’t break any programs. Sometimes, however, we conclude that the change is important to make and “compatible” even though it does break some programs. In that case, we still work to reduce the impact as much as possible, and then we document the potential problem in the release notes.
Here are two examples of that kind of subtle compatibility problems we found by testing Go inside Google but still included in Go 1.1.
Here is some code that runs fine in Go 1:
Package main declares a global variable myAddr, which is a composite literal of type net.TCPAddr. In Go 1, package net defines the type TCPAddr as a struct with two fields, IP and Port. Those match the fields in the composite literal, so the program compiles.
In Go 1.1, the program stopped compiling, with a compiler error that said “too few initializers in struct literal.” The problem is that we added a third field, Zone, to net.TCPAddr, and this program is missing the value for that third field. The fix is to rewrite the program using tagged literals, so that it builds in both versions of Go:
Since this literal doesn’t specify a value for Zone, it will use the zero value (an empty string in this case).
This requirement to use composite literals for standard library structs is explicitly called out in the compatibility document, and go vet reports literals that need tags to ensure compatibility with later versions of Go. This problem was new enough in Go 1.1 to merit a short comment in the release notes. Nowadays we just mention the new field.
The second problem we found while testing Go 1.1 had nothing to do with APIs at all. It had to do with time.
Shortly after Go 1 was released, someone pointed out that time.Now returned times
本页为82搜索生成的网页快照,内容来自站内索引;演示数据的原文链接仅作示例。