Question about for loop for iterate a collection

Hi experts,

I am new to golang, actually how go is working with go loop under the cover with a collection of data.

take following code as example:

package main

import "fmt"

func main() {
	myMap := map[string]int{
		"a": 1,
		"b": 2,
		"c": 3,
		"d": 4,
	}
	fmt.Println(myMap)
	for k, _ := range myMap {
		if k == "b" {
			delete(myMap, k)
		}
	}
	fmt.Println(myMap)
}

My question is when go interating the collection, is it making the copy of the collection to do the iteration? Or the reference.
Another question what happens if i delete the key within the loop(or change the content of that collection), how is go is going to position the index especially when dealing with slice.

Thanks a lot

BR//

No.

It’s OK to delete key.

Note: if the map is being accessed by multiple go routines, then you’ll need to wrap the for… loop with a sync.RWMutex or use a sync.Map.

The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If map entries that have not yet been reached are removed during iteration, the corresponding iteration values will not be produced. If map entries are created during iteration, that entry may be produced during the iteration or may be skipped. The choice may vary for each entry created and from one iteration to the next. If the map is nil, the number of iterations is 0.

Via https://golang.org/ref/spec#For_statements and emphasis added by me.

I don’t see anything in the spec specifying whether a copy happens or not (you may want to check yourself though), so my best guess is that this isn’t guaranteed behavior. As a result, I wouldn’t recommend relying on that behavior regardless of which it is, because anything not specified in the spec could change on you.

2 Likes

Hi,

You are right, behavior is not the same for different runtime.

package main

import "fmt"

func main() {
	example1()
	example2()
}

func example1() {
	fmt.Println("##############Example 1####################")
	myMap := map[string]int{
		"a": 1,
		"b": 2,
		"c": 3,
		"d": 4,
	}
	for k, _ := range myMap {
		if k == "b" {
			delete(myMap, k) //It's safe to do this even if the key is already absent from the map.
		}
	}
	fmt.Println(myMap)
}

func example2() {
	fmt.Println("##############Example 2####################")
	myMap := map[string]int{
		"a": 1,
		"b": 2,
		"c": 3,
		"d": 4,
	}
	i:=0
	for k, _ := range myMap {
		fmt.Println("Printting:", k)
		if _, present := myMap["c"]; present {
			delete(myMap, "c")
		}
		fmt.Println("Printting:", k)
		i++
	}
	fmt.Println(i)
	fmt.Println(myMap)
}

Printout 1:
##############Example 1####################
map[d:4 a:1 c:3]
##############Example 2####################
Printting: a
Printting: a
Printting: b
Printting: b
Printting: d
Printting: d
3
map[a:1 b:2 d:4]

Printout 2:
##############Example 1####################
map[c:3 d:4 a:1]
##############Example 2####################
Printting: c
Printting: c
Printting: d
Printting: d
Printting: a
Printting: a
Printting: b
Printting: b
4
map[d:4 a:1 b:2]

Interesting to know and need to be careful when doing similar things.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.