🕌

Go言語のmapをrangeでループすると、取り出す順番はランダムになる

2021/10/15に公開

Go言語でmapをrangeでループさせると、取り出す順番がランダムになる、というメモ

実装

以下のコードを実行すると、出力される値の順番が実行する毎に変わります。

package main

import "fmt"

func main() {
	m := map[int]string{
		1: "value1",
		2: "value2",
		3: "value3",
	}

	for key, value := range m {
		fmt.Println(key, value)
	}
}
1回目
2 value2
3 value3
1 value1
2回目
3 value3
1 value1
2 value2

なぜ順番がランダムになるのか

古い言語仕様では、マップの反復順序が定義しておらず、ハードウェアプラットフォーム間で実行順が異なっていた。
反復順序に依存すると移植性がなくなるため、ランダム性を持たせている。

というのがこの挙動の理由みたいです。

https://golang.org/doc/go1#iteration

順番を固定したい場合

mapのキーをsliceに入れて、それを基準にループする、といった実装をすればmapの順序を固定することができます。

package main

import (
	"fmt"
	"sort"
)

func main() {
	m := map[int]string{
		1: "value1",
		2: "value2",
		3: "value3",
	}
	var keys []int
	for k := range m {
		keys = append(keys, k)
	}
	sort.Ints(keys)
	for _, k := range keys {
		fmt.Println("Key:", k, "Value:", m[k])
	}
}

https://go.dev/blog/maps#iteration-order

Discussion