Friday, December 6, 2019

GoLang: Map Values retrieved as Reference or by Value ?

GoLang Map Value : By Value or Reference ?

Map data structure in GoLang is to map keys to values.

Value Retrieval

If we have a map say objects with keys as string, then we retrieve a value for any key as
objects["key"]

is Value a reference or new value?

Having come from Java background, my idea was the value retrieved from map was going to be by reference. This was not true. Value retrieved from map by above fashion actually returns new object.

So if the value in the map is some struct, then any updated on the extracted value is not reflected.

Example

In this example,
  1. we retrieve a value from a map
  2. We update the value
  3. retrieve the same value from map again
Here we can see the update is not reflected into the map. RUN THE CODE

package main

import (
  "fmt"
)

type Person struct {
  Name string
  Address string
}

func main() {
  persons := map[string]Person {
    "ginny" : Person {
      Name : "ginny",
      Address: "Hogwart",
    },
  }
  
  person := persons["ginny"]
  fmt.Println(person) // will print ginny and Hogwart as expected
  
  person.Address = "Three Brooms"
  fmt.Println(person) // will print ginny and Three Brooms as expected. But this is not updated into Map
  
  person = persons["ginny"]
  fmt.Println(person) // will print ginny and Hogwart not the updated values
}

What to do for reflecting the update into map?

If you want the update in value to be reflected into the map, then the mapping in map should be pointer.
persons := map[string]*Person
This is same example as above. Only we are using pointer values in the map. Here we are able to see that the update is reflected into the map. RUN THE CODE

package main

import (
  "fmt"
)

type Person struct {
  Name string
  Address string
}

func main() {
  persons := map[string]*Person {
    "ginny" : &Person {
      Name : "ginny",
      Address: "Hogwart",
    },
  }
  
  person := persons["ginny"]
  fmt.Println(*person) // will print ginny and Hogwart as expected
  
  person.Address = "Three Brooms"
  fmt.Println(*person) // will print ginny and Three Brooms as expected. But this is not updated into Map
  
  person = persons["ginny"]
  fmt.Println(*person) // will print ginny and Three Brooms as expected
}

Similar Other Cases

  1. Method Receiver : If a method updates the receiver, then receiver should be pointer in order to reflect the updates. RUN Example
  2. Slice : When objects from slices are retrieved and updated, update is not reflected in slice itself. Pointer should be used to reflect the update. RUN Example