Need help understanding `map` behaviour

Please have a look at the code gist

I am trying to append new dayContributions to the array weekContributions.AllDays.
[Line 24] is the part appends to the AllDays property of the current type weekContributions.

[Line 47-49] is the part that calls the function. The print statement prints the weekContributions array with a single member in the array. But the following print statement [Line 51] says that all map values i.e. weekContributions objects have empty arrays as AllDays property.

My aim - To append dayContribution objects to values in map activity.yearContributions [Line 28]

I think -

  1. The append function is working as intended as it appends 1 member on each iteration
  2. Somehow, the currentWeekContribution.addContribution line here is only appending to the local variable currentWeekContribution and doesn’t update the corresponding value in currentActivity.yearContributions map

I am very new to golang and I think I am not following the go way / this would have worked in java or ruby
I don’t know what this behaviour is called, so can’t google search anything relevant.

Hi @vedharish, here’s my quick solution. In your func (currentActivity *Activity) restore() AllDays: make([]dayContributions, 0) it use same address of memory and it’s length is set to zero. In my solution I used pointer to allocate new address in memory in AllDays.

package main

import (
	"fmt"
	"time"
)

type Activity struct {
	yearContributions map[string]weekContributions
}

type dayContributions struct {
	Date         time.Time
	Contribution int
}
type weekContributions struct {
	Notation string
	AllDays  *[]dayContributions
}

func (currentWeekContribution *weekContributions) addContribution(additionalDayContribution dayContributions) {
	*currentWeekContribution.AllDays = append(*currentWeekContribution.AllDays, additionalDayContribution)
}

func (currentActivity *Activity) restore() {
		currentActivity.yearContributions = map[string]weekContributions{
	"Sunday":    weekContributions{Notation: "S", AllDays:&[]dayContributions{}},
	"Monday":    weekContributions{Notation: "M", AllDays:&[]dayContributions{}},
	"Tuesday":   weekContributions{Notation: "T", AllDays:&[]dayContributions{}},
	"Wednesday": weekContributions{Notation: "W", AllDays:&[]dayContributions{}},
	"Thursday":  weekContributions{Notation: "T", AllDays:&[]dayContributions{}},
	"Friday":    weekContributions{Notation: "F", AllDays:&[]dayContributions{}},
	"Saturday":  weekContributions{Notation: "S", AllDays:&[]dayContributions{}},
		}
}
func (currentActivity *Activity) Recalibrate() {
	
	currentActivity.restore()
	endDate := time.Now().UTC()
	startDate := endDate.AddDate(-1, 0, 0)
	
	for d := startDate; endDate.After(d); d = d.AddDate(0, 0, 1) {
	
		stringWeekday := d.Weekday().String()
		currentWeekContribution := currentActivity.yearContributions[stringWeekday]
		fmt.Println(d,stringWeekday)
		currentWeekContribution.addContribution(dayContributions{Date: d, Contribution: 1})
	}
	
	fmt.Println(currentActivity.yearContributions["Monday"].AllDays) 
	// prints : map[Tuesday:{T []} Wednesday:{W []} Thursday:{T []} Friday:{F []} Saturday:{S []} Sunday:{S []} Monday:{M []}]
}



func main() {
	
	a := Activity{}
	a.Recalibrate()
currentWeekContribution := currentActivity.yearContributions[stringWeekday]

(line 47)

currentWeekContribution is a copy of the value from currentActivity.yearContributions[stringWeekday].

Since it is a copy, changing it does not change the value stored in the map. There are basically two ways to achieve the behaviour you seem to want:

  1. set the map value after you are done manipulating it (e.g., currentActivity.yearContributions[stringWeekday] = currentWeekContribution)
  2. Use a map of pointers:
type Activity struct {
	yearContributions map[string]*weekContributions
}

The pointer will then be copied, but since both copies point to the same value, that value can be manipulated without having to update the map.

2 Likes

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