GoにはGo 1 promise of compatibilityがあり基本的にGo1.xでAPIのインターフェースが変更されることはない.そのため過去に書いたコードを新しいGoでビルドしてもぶっ壊れることは(おそらく)ない.ただリリースごとに新しいパッケージや関数/メソッドはどんどん追加されていくため古いGoで新しいコードをビルドすることはできないことがある(例えば,標準のcontextパッケージを使っているコードはGo1.7以降でしかビルドすることができない).
GoはリリースごとにGC(e.g., Sub-millisecond GC pauses)やコンパイラ(e.g, SSAの導入)や各標準パッケージの改善が行われる.そのため自分は「どんどんバージョン上げていけば良い.だからパッケージも同じく最新のバージョンで動くものを提供すれば良い」と思う.がこれは個人的な思想で誰かが使える形でインターネットに公開している限りは横暴でもある.少なくとも移行期(以下の図でいうとStage2)を持たせるのが真摯な姿勢だと思う.
https://talks.golang.org/2016/refactor.article
新しいバージョンのGoを使っているユーザには新たに追加された関数/メソッドを利用可能にしつつ,古いバージョンのGoを使っているユーザのビルドを壊さないようにするにはBuild Constraintsを使えば良い.
例えば以下のようなmain関数を考える.
func main() {
fmt.Println(Hello())
}
このときGo1.8以降でしか使えない関数/メソッドを使ったHello
とそれ以前のバージョン用のHello
を提供するには以下のように2つのファイルを準備すれば良い.
// +build go1.8
package main
func Hello() string {
return "Hello (after go1.8)"
}
// +build !go1.8
package main
func Hello() string {
return "Hello (old version)"
}
go1.8
のビルドタグを持つファイルはGo1.8以降(betaも含む)のビルドに使われ!go1.8
のタグを持つファイルはそれ以前の古いバージョンのビルドにのみ利用される.
まとめ
特に最近は標準パッケージがcontext
対応を始めているのでこれを利用する機会は増えるのではないか.やりすぎは良くない気もするのであくまで移行期のための手段とするのが良いと思う.ある程度経ったら古いバージョンは切り捨てればいい.
参考
Build ConstraintsについてはみんなのGo言語のmattnさんの章に詳しい解説がある.またmattnさんはgo-sqlite3で同様の対応をしている(sqlite3_go18.go).自分も最近go-httpstatで同様にGo1.8の対応をした(#10).
標準パッケージだとxのcontextパッケージが同様のことをしている.