0

I have written pointer receiver method with struct A and created two functions

  1. expect A type slice as parameter and
  2. expect map[int]A type Map as parameter.

Both iterate through the values and called pinter receiver method of A. But when it called in map there is a compile error mentioned in below. Both slice element value and map value is main.A

./main.go:28:8: cannot call pointer method on aa[k]
./main.go:28:8: cannot take the address of aa[k]

Code with compilation error is commented and code is below.

package main

type A struct {
    I int
}

func (a *A) Add(i int)  {
    a.I += i
}

func main()  {
    aa2 := []A{{I:5}}
    testSlice(aa2, 10)
    //aa1 := map[int]A{
    //  5: {I:5},
    //}
    //testMap(aa1, 10)
}

func testSlice(aa []A, i int)  {
    for k := range aa {
        aa[k].Add(i)
    }
}

//func testMap(aa map[int]A, i int)  {
//  for k := range aa {
//      aa[k].Add(i)
//  }
//}

Uncommented code is here

Please help me to clear about this, why is this compile error happening?

nipuna
  • 3,697
  • 11
  • 24
  • 5
    the short answer is that map values are non addressable. –  Aug 06 '21 at 11:39
  • 2
    rather than trying to quote the spec, i figured that this link was really good https://utcc.utoronto.ca/~cks/space/blog/programming/GoAddressableValues –  Aug 06 '21 at 11:43
  • 2
    as to what happens internally, this should help https://stackoverflow.com/questions/38168329/why-are-map-values-not-addressable –  Aug 06 '21 at 11:44

2 Answers2

0

In go, map values are not addressable. This means that you cannot get a pointer pointing to a map value (aa[k]), and thus you cannot call a method with a pointer receiver on this value.

The workaround is the following:

for k := range aa {
        e := aa[k]
        e.Add(i)
        aa[k] = e
    }
aureliar
  • 1,476
  • 4
  • 16
0

First thanks for the go playground it really helps.

Well your method uses a pointer receiver, and maps, are used to store a key-object, as aureliar said, maps in go are not addressable ( Why doesn't Go allow taking the address of map value? ),so what you need to do is this : Doing a range on maps, the 1° value is the key, and the second is the value So your struct is saved in memory as a Key : Struct.

One option is declare that map as :

map[int]*A 

So when you peek up the value from the map, you can access the pointer method.

for _,value := range aa {
        value.Add(i)
}

Heres the playground: https://play.golang.org/p/eVA8ujrdcO4

Other solution you can keep the map as map[i]A, just in the for range: give the value back to its key, like this:

for k,value := range aa {
        value.Add(i)
        aa[k]=value
    } 

Here is the playground: https://play.golang.org/p/k-Qr8oYpL6j