💻 Tech
One best practice in Go programming is consistency with the data semantics. If you will use data semantics, use it across the funcction as much as possible. Same goes with pointer semantics. In the sample code below, a pointer is created for the player in the 3rd index. However, after the append, it went awry. The score didn’t accumulate. It’s expected to be 2. The reason is, in the beginning, players already have len=3 and cap=3. When that happens, append will create a new backing array. The problem with player3 pointer is it still points to the old backing array, while the players slice already got a new backing array. Moreover, the pointer still locks the memory that could have been released by the garbage collector.
The key lesson here is to be mindful of making a pointer from a slice item. append dynamically changes the underlying/backing array, and knowing that will make developers make preemptive actions when dealing with slice items.
Demo program:
func main() {
players := make([]player, 5)
display(players)
player3 := &players[3]
player3.score++
display(players)
players = append(players, player{})
player3.score++
display(players)
}
func display(players []player) {
for i, v := range players {
fmt.Printf("%v %v\n", i, v.score)
}
fmt.Println()
}
Output:
0 0
1 0
2 0
3 0
4 0
0 0
1 0
2 0
3 1
4 0
0 0
1 0
2 0
3 1 # score still 1; should be 2
4 0
5 0