okaryo.log

Be Careful with Pointers in Go's range (A Personal Reminder) | okaryo.log

Be Careful with Pointers in Go's range (A Personal Reminder)

    #Go

Introduction

Recently, while developing a Go server, I encountered unexpected behavior.

After investigating, I found that the issue was related to how I was using pointers inside a range. In this post, I want to document the problem and its solution as a reminder to myself.

Problematic Code

The code I was working on was quite different, but to illustrate the issue, I’ve prepared the following example. In this code, a slice called userPtrs is populated with pointers to elements of users within a range.

package main

import "fmt"

type User struct {
	Name string
}

func main() {
	users := []User{
		{"Alice"},
		{"Bob"},
		{"Charlie"},
	}

	var userPtrs []*User
	for _, user := range users {
		userPtrs = append(userPtrs, &user)
	}

	for _, u := range userPtrs {
		fmt.Println(u.Name)
	}
}

At first glance, this code seems correct, but when you run it, the output is as follows. All elements point to the last element of users.

Charlie
Charlie
Charlie

Cause and Solution

The root of this problem is that the user variable used in the range loop is being overwritten in each iteration. Although it should be obvious, the range loop defines a user variable, which is simply reassigned in each iteration to the next element. In other words, the pointer to the user variable remains the same throughout the range.

As a result, all elements in the userPtrs slice end up pointing to the same memory address, which is the state of the user variable after the last iteration.

To avoid this, you can create a new variable that directly references the element in users using its index.

for i := range users {
	user := users[i]
	userPtrs = append(userPtrs, &user)
}

This produced the expected result.

Conclusion

A similar topic is the use of anonymous functions in a range loop when dealing with goroutines, but there are likely other pitfalls related to range.

To prevent such issues, it’s essential to write tests for any areas that seem concerning. In this case, tests saved me once again.


Related Posts
Related Posts
Promotion

This site uses Google Analytics.