hbagdi
hbagdi

Reputation: 485

Changing reference of struct inside struct

I've been trying to update a map variable inside a struct but with no luck.

I expected that maps in Golang are passed by reference and hence assigning one reference to another should work but that's not the case.

I might be missing something obvious here, and if that's the case, apologies!

package main

import (
        "fmt"
)

type Foo struct {
        t map[string]interface{}
}

func (F Foo) Set(ta map[string]interface{}) {
        F.t = ta
}
func (F Foo) Get() map[string]interface{} {
        return F.t
}

func main() {
        t := make(map[string]interface{})
        t["t"] = "sf"
        t["array"] = []int{1, 2, 3}

        fmt.Println(t) // prints map[t:sf array:[1 2 3]]
        var f Foo

        f.Set(t)
        // why the following?
        fmt.Println(f.t) //prints map[]

        f.t = t
        fmt.Println(f.t) //prints map[t:sf array:[1 2 3]]
}

Playground: https://play.golang.org/p/i1ESV1BdjGQ

Upvotes: 1

Views: 1095

Answers (1)

Ullaakut
Ullaakut

Reputation: 3734

Basically, you need a pointer receiver on your Set method to be able to change the state of your structure.

Methods with pointer receivers can modify the value to which the receiver points. Since methods often need to modify their receiver, pointer receivers are more common than value receivers.

Get should also have a pointer receiver for consistency:

Next is consistency. If some of the methods of the type must have pointer receivers, the rest should too, so the method set is consistent regardless of how the type is used. See the section on method sets for details.

See a tour of go for more examples.

Here is a fix of your code:

package main

import (
    "fmt"
)

type Foo struct {
    t map[string]interface{}
}

func (F *Foo) Set(ta map[string]interface{}) {
    F.t = ta
}
func (F *Foo) Get() map[string]interface{} {
    return F.t
}

func main() {
    t := make(map[string]interface{})
    t["t"] = "sf"
    t["array"] = []int{1, 2, 3}

    fmt.Println(t)
    var f Foo

    f.Set(t)
    fmt.Println(f.Get()) //prints map[t:sf array:[1 2 3]]

    f.t = t
    fmt.Println(f.Get()) //prints map[t:sf array:[1 2 3]]
}

Outputs

map[t:sf array:[1 2 3]]
map[t:sf array:[1 2 3]]
map[t:sf array:[1 2 3]]

Try it yourself here

Upvotes: 2

Related Questions