Go Conference

Room B

All

20 mins.

Go1.22から(プレビューはGo1.21から)ループ変数のメモリ共有問題が解消されたことは皆様よくご存知かと思います。 cf. Fixing For Loops in Go 1.22

それではもう1歩踏み込んで、ループ変数に新しいメモリが割り当てられるのはどのような時なのでしょうか?以下2つの出力が異なる理由をどう説明できるでしょうか?

for i := range 3 {
	fmt.Print(&i) // [0x14000112018, 0x14000112030, 0x14000112038] // 異なるアドレス
}
for i := range 3 {
	print(&i) // [0x1400010af18, 0x1400010af18, 0x1400010af18] // 同じアドレス
}

新しいループとそれを取り巻くツールの実装は、既存コードでバグを生み出さない・パフォーマンスを落とさない工夫がされています。

本セッションでは、loopvarパッケージのコードリーディングを通して、これら変更の背後にある内部動作を解説します。 さらに、デザインドキュメントやコミュニティでの議論はもちろん、周辺ツールやアセンブリベースでの挙動変更なども併せて確認することで、ループ変数への理解をより深めたいと思います。

また、Go1.22から不要になったループ変数のコピーを検出する自作linter copyloopvar をgolangci-lintにコントリビュートした話もお伝えします。 このlinterが何をどのように検知するかを紹介する中で、Goにおける静的解析ツールの作成方法も解説します。 linterの自作やOSS貢献に一歩踏み出す際、本セッションがご参考になれば幸いです。

唐木 稜生

唐木 稜生

株式会社サイバーエージェント

ゲームのバックエンドエンジニアです。ボーカロイドが好きです。