🦔

Goのマップの反復処理の順序は保証されていない

2024/09/06に公開

はじめに

Goのマップにおいて、反復処理の操作を行う際の順序は保証されていません。これは多くの開発者が見落としがちな仕様です。

動作確認してみる

コードベースで具体的に見てみましょう。

package main

import "fmt"

func main() {
	m := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}
	for k := range m {
		fmt.Print(k)
	}
	fmt.Println()
}

上記を何度か実行すると以下のような出力になります。

edcba
caebd
deabc

このように毎回出力の順番が異なるのがわかりますね。

なぜ違うのか?

これは言語設計者が意識的に選択したものです。設計者は、開発者がマップを扱うときの順序の仮定に依存しないよう、意図的にランダム性を追加しました。

Go 1.0のリリースノートには以下のように記載されています。

Iterations over small maps no longer happen in a consistent order.
Go 1 defines that "The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next."
To keep code from depending on map iteration order, Go 1.0 started each map iteration at a random index in the map.

ref: https://github.com/golang/go/commit/d1f627f2f3f6fc22ed64e1cc7b17eefca952224b

以下要約です

マップの反復処理の順序は仕様で定義されておらず、保証されていません。
開発者がマップの反復順序に依存しないようにするため、Go 1.0からはマップの反復処理をランダムな位置から開始するようになりました。
これは小さなマップでも適用され、システムやイテレーションごとに順序が変わる可能性があります。

まとめ

Goのマップでは、反復処理の操作を行う際の順序は意図的に保証されていません。これは言語設計の重要な特徴であり、私たち開発者はそれを理解した上でGoらしいコードを書く必要があります。

Discussion