Can't index pointer to map?

Something I’ve noticed as a Go novice that I’d like an explanation on:

Let’s say I have a map that I pass by reference to a function

myMap := make(map[string]int)

myFunc(&myMap)

Inside of the func, I have to copy that map to a local variable in the function, modify that, then re-copy it before the map that I want to modify is actually modified:


func myFunc(tMap *map[string]int) {
	tmpMap := *tMap

	tmpMap["Goose"] = 11
	tmpMap["Gander"] = 11

	*tMap = tmpMap
}

This wouldn’t work if I tried to directly modify the map that I passed in. For instance the below:

func myBrokeFunc(tMap *map[string]int) {
	tMap["Goose"] = 14
	*tMap["Gander"] = 14

}

causes my IDE to complain in both instances that I can’t index a pointer to a map.

What is the cause of this? I understand that there could be issues with concurrent writes, but that would be the case with other variables that I can do this with. This is a very interesting problem to me, and I’d love to know what’s going on under the hood.

There’s no reason to pass a pointer to a map. Just pass the map, it won’t copy the contents.

Bellow article should clarify your question about how the map works.

https://dave.cheney.net/2017/04/30/if-a-map-isnt-a-reference-variable-what-is-it

Exactly
However let me expose what is the reason of the message “does not support indexing”
when you write

*tMap["Gander"] = 14

The compiler see that expression like

*(tMap["Gander"]) = 14

And here comes the message tMap does not support indexing because is a pointer.
Just write something like

(*tMap)[“Gander”] = 14

that way Go resolves the expression in parentheses first and returns the pointed object, which is a map and there you can use it as usual

3 Likes

map is a reference type, the original data of the function transfer map will change, no need to use the *map type

1 Like

+1 @Yamil_Bracho

maps are a special data type, they are not a struct, nor a pointer to a struct (pointer to a runtime.hmap object), but something close to that.

Every time you use a map, at compile time your map-related code will be replaced by auto generated code. This creates limitations into how you can work with maps (and how you should think about them).

@Yamil_Bracho gave the right answer, use (*tMap)[“Gander”] = 14

1 Like

On the other hand using pointers on maps is not such a good idea because:

Of all of Go’s built in data structures, maps are the only ones that move data internally. When you insert or delete entries, the map may need to rebalance itself to retain its O(1) guarantee. This is why map values are not addressable .

https://dave.cheney.net/2015/12/07/are-go-maps-sensitive-to-data-races

Thanks everyone for all the great answers! This has been really enlightening.

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