🌊

Goのバージョン1.21以降はライブラリとのバージョン差によるバグが減るらしい

2023/12/25に公開

これは CastingONE Advent Calendar 25日目の記事です。

はじめに

CastingONEでバックエンドエンジニアをやっている清水です。
本記事では、Go 1.21のリリースに伴い加わったツールチェーンの新機能により前方互換性が向上したようなので、その内容について説明していきます。
少しイメージがしにくい場合は、手を動かして挙動を確認できるように検証用のコードを用意したのでご確認いただければと思います。

リリースによって追加されたのはどのような機能か?

Go 1.21のリリースによって追加されたツールチェーンの機能は、Goのコードの前方互換性を向上させるものです。
これは、プロジェクトのgo.modファイル内のgo行を使って、必要なGoツールチェーンのバージョンを指定することによって実現されます。
古いGoのバージョンが新しいコードをコンパイルする際の失敗を防ぎます。また、必要に応じてgoコマンドが自動的に新しいGoツールチェーンをダウンロードして実行する機能も追加されました。これにより、異なるプロジェクトで異なるGoのバージョンを簡単に管理できるようになります。

なぜ必要なのか?

新しいGoのバージョンで追加された機能やバグ修正に依存するコードが、古いGoのバージョンで誤ってコンパイルされることで、意図しないエラーが発生することを防ぐために機能追加されました。

https://go.dev/blog/toolchain

The main reason we allowed older versions of Go to try to compile newer code was to avoid unnecessary build failures. It’s very frustrating to be told that your version of Go is too old to build a program, especially if it might work anyway (maybe the requirement is unnecessarily conservative), and especially when updating to a newer Go version is a bit of a chore. To reduce the impact of enforcing the go line as a requirement, Go 1.21 adds toolchain management to the core distribution as well.

問題が発生する具体的なケース

ここでは想像しやすいように少し具体的なケースを書いていきます。
自身のgo.modのバージョンが1.17で、あるライブラリのGet()というメソッド内でgo1.18でリリースされたジェネリクスを利用しているケースを考えていきます。
1.21がリリースされる前までは、自身が定義したgo.modのバージョン1.17で実行されるのでGet()メソッドのジェネリクスを利用している箇所でコケます。
1.21以降では、エラーにならない最小のバージョンで実行されるようになり、バージョン差によるエラーは発生しなくなります。

検証方法

さらに想像しやすいように、こちらの記事を参考に検証してみました。説明を詳しく確認したい場合は元の記事も参考にしていただければと思います。

手元で動かしながら確認されたい方は以下のリポジトリで試すことができるので使ってもらえればと思います。
go.modファイルを1行修正してgo mod tidyするだけで再現できるようになっています。

https://github.com/shimizu-katsunori-cas/go-toolchain

ここでは紹介したリポジトリの概要を説明していきます。

1. go.modは参照しているライブラリよりもバージョンが高い状態でgo mod tidyを実行

l3側のgo.mod

l3/go.mod
module github.com/shimizu-katsunori-cas/go-toolchain/l3

go 1.21.0

参照している側のgo.mod

go.mod
module github.com/shimizu-katsunori-cas/go-toolchain

go 1.21.0

require (
	github.com/shimizu-katsunori-cas/go-toolchain/l1 v0.0.1
	github.com/shimizu-katsunori-cas/go-toolchain/l2 v0.0.1
	github.com/shimizu-katsunori-cas/go-toolchain/l3 v0.0.1
)

github.com/shimizu-katsunori-cas/go-toolchain/l3 v0.0.1ではgo 1.21.0のバージョンを利用しており、参照している側のgo.modは一番バージョンが高い状態を保っている

2. 参照している側のgo.modよりもl3のgo.modの方がバージョンが高くなるように修正

l3側のgo.mod

l3/go.mod
module github.com/shimizu-katsunori-cas/go-toolchain/l3

go 1.21.3

参照している側のgo.mod

go.mod
module github.com/shimizu-katsunori-cas/go-toolchain

go 1.21.0

require (
	github.com/shimizu-katsunori-cas/go-toolchain/l1 v0.0.1
	github.com/shimizu-katsunori-cas/go-toolchain/l2 v0.0.1
	github.com/shimizu-katsunori-cas/go-toolchain/l3 v0.0.3
)

github.com/shimizu-katsunori-cas/go-toolchain/l3 v0.0.3ではgo 1.21.3のバージョンを利用しており、参照している側のgo.modよりもl3のGoのバージョンの方が高い状態になった

3. go mod tidyを実行

参照している側のgo.mod

go.mod
module github.com/shimizu-katsunori-cas/go-toolchain

go 1.21.3

toolchain go1.21.5

require (
	github.com/shimizu-katsunori-cas/go-toolchain/l1 v0.0.1
	github.com/shimizu-katsunori-cas/go-toolchain/l2 v0.0.1
	github.com/shimizu-katsunori-cas/go-toolchain/l3 v0.0.3
)

go mod tidyの結果go.modの中身が自動で書き換わっており、Goやツールチェインのバージョンがl3のGoのバージョン以上になっていることを確認

おわりに

弊社ではいっしょに働いてくれるエンジニアを募集中です。社員でもフリーランスでも、フルタイムでも短時間の副業でも大歓迎なので、気軽にご連絡ください!

https://www.wantedly.com/projects/1130967

https://www.wantedly.com/projects/1063903

Discussion