2

I wrote some code which does this, and it is working fine, but when reviewing the code I realize what I did might not have worked in other languages.

To give a contrived example:

dict := map[string]string{ "a": "1", "b": "2" }

for key, val := range dict {
  fmt.Println(val)
   delete(dict, "b")
}

This prints "1" and "2", and when I inspect dict afterward it is { "a": "1" } only.

So, I get the impression that it is safe to do this, but I'm wondering why?

Does range dict create a copy internally?

max pleaner
  • 26,189
  • 9
  • 66
  • 118
  • 2
    @colminator not a duplicate. The OP is asking if a further element would be printed if it's deleted in previous iteration. – Berkant İpek May 08 '19 at 20:12
  • 1
    The OP is _not_ asking that. – colm.anseo May 08 '19 at 20:17
  • 2
    Well, the actual question is is nearly identically worded as [Is it safe to remove selected keys from map within a range loop](https://stackoverflow.com/questions/23229975/is-it-safe-to-remove-selected-keys-from-map-within-a-range-loop), and the answer regardless is just quoted from the spec. – JimB May 08 '19 at 20:18
  • they are sort of two sides of the same coin ... that question focuses on the case when it _is_ safe, but my question is more specifically about the case when it is unsafe (my code in the question) – max pleaner May 08 '19 at 20:53
  • 2
    But it _is_ safe, so how do the questions differ? Also, iteration order is non-deterministic, so your example may print one or both values at runtime. – JimB May 08 '19 at 21:54
  • Ok, maybe "safe" isn't the right term, but my code in the question wouldn't _dependably_ do as intended – max pleaner May 08 '19 at 22:44

1 Answers1

4

As always, the spec is the definitive answer. Under "For statements with range clause", item 3 (emphasis mine):

The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If a map entry that has not yet been reached is removed during iteration, the corresponding iteration value will not be produced. If a map entry is 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.

amalloy
  • 89,153
  • 8
  • 140
  • 205
  • Thank you for this. So, my example in the question would not dependably work. What about if I only delete the key being currently processed (similar to Ruby's [delete_if](https://apidock.com/ruby/Array/delete_if))? That would be safe, because the map entry being removed _has_ already been reached during iteration? – max pleaner May 08 '19 at 20:11
  • 1
    @maxpleaner If I get it right, if you delete the key in the same iteration, it would still work because it's already loaded in `key` and `val` of the loop. – Berkant İpek May 08 '19 at 20:18