Không. Spec quy định thứ tự lặp trên map là không xác định, và runtime còn cố tình ngẫu nhiên hóa điểm bắt đầu mỗi lần chạy để lập trình viên không lỡ phụ thuộc vào nó.
go
m := map[string]int{"a": 1, "b": 2, "c": 3}
for k, v := range m {
fmt.Println(k, v) // thứ tự khác nhau giữa các lần chạy
}Muốn ổn định thì sắp xếp khóa rồi duyệt:
go
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Println(k, m[k])
}Bẫy hay gặp trong thực tế:
- Test so sánh chuỗi output sinh từ map sẽ lúc pass lúc fail.
- Sinh câu SQL hay chữ ký request (HMAC) từ map mà không sắp khóa sẽ cho kết quả khác nhau mỗi lần.
- encoding/json là ngoại lệ: Marshal tự sắp xếp khóa map, nên JSON output vẫn ổn định.
Sửa map trong lúc range: khóa mới thêm có thể xuất hiện hoặc không; khóa vừa delete chắc chắn không được duyệt tới nữa. Xóa trong lúc duyệt là hợp lệ, còn thêm thì nên tránh.