Introduction

Go is a statically typed compiled programmin language that was created by Google back in 2009. Since Go is a very generic world if you search for Go on Google you are going to get a lot of results that have nothing to do with the awesome Go programming language. To avoid that issue people, when searching things related to programming use golang and some people think the name of the language is that one because it is so common on Google, but that is not the case, the real name of the programming language is just Go. Ok, this has nothing to do with I am going to present you below but I wanted to write a little about that for myself. Thank you for your attention so far. Now, let’s do what we have come to do here, talk about handling reference to loop iterator variable in Go.

I am kinda new to Go and I say new that way because it wasn’t recently, like a month or two ago that I have started coding in Go. The first I used Go was back in 2018. For some reason, I don’t know exactly what I was looking for but I ended up finding about Go on the interned and decided to experiment with and liked the language and used the language for about six months back then. After that period I moved away from Go not because I did not the language. I like this language a lot, but I was working with other stuff like JavaScript, React and Node, but now at the end of 2022 I have decided to invest some time on Go again because I wanted to focus more on back-end development and Go has some nice characteristics that I really like. Those are:

  • It is a compiled language. That means you write your code, compile id down to a native binary and ship that binary to production.
  • It is statically typed.
  • It is simple, in my opnion. It is a language you can learn enough to ship something in less than a week
  • It comes with a nice standard library
  • It is opnionated on things like formatting, unused vars, modules and so on
    • It has a tool that formats the code for you
    • If you declare a variable and do not use it your code will not compile

How I ended up here

I am building a REST API in Go using Chi for routing and pgx + sqlx for database access. PostgreSQL, my go-to database, is being used to store the data.

This is my first time building a REST API with Go. How to structure that king of project in Go? Well, I really didn’t know before starting this project. What I did was looking up some examples of repositories on Github and then copy that one into my project. Imagine you’re new to a programming language but you already have experience building the same kind of stuff on other languages, would you build everying from scratch? I chose not to do that but instead use a boilerplate that cover most the things I need when building an API. I have achieved that with the following repositories as an starting point:

The API, so far, is a CRUD on the users table. Bear with me, this is not a simple CRUD. It is an awesome REST API that allows you to create, read, update and delete users. That API comes with pagination so that you won’t be fetching the users table but limiting the result to just 10 or 20 rows when you hit the GET /api/users endpoint. What happens when you hit this endpoint is the following: You have the option to set pagination params which are page (the page number) and per_page (size of the list of users returned). By default page is 1 and per_page is 20. With pagination being passed, the enpoint becomes GET /api/users?page=1&per_page20.

With Chi, you write the handler and associate that handler with a route by doing the following:

// ... resource definition
func (r resource) listUsers(w http.ResponseWriter, req *http.Request) {
  users, err := r.service.Query(0, 20)
  ...
}

router := chi.NewRouter()
r.Get("/api/users", listUsers)
// ...

That listUsers handler function, call the users service, which in turn calls the users repository. The user repository has a GetUsers function which sends a query to the database to retrieve the users.

// ... other stuff like `userQueries` definition and db connection above
func (q *userQueries) GetUsers(offset, limit int) ([]entity.User, error) {
	users := []entity.User{}

	query := `SELECT * FROM users ORDER BY id LIMIT $1 OFFSET $2`

	err := q.db.Select(&users, query, limit, offset)

	return users, err
}
// ...

So far, everything works as expected. Now comes the part where I got in trouble with reference to Loop Iterator Variable.

Reference to Loop Iterator Variable in Go

When returning data to the client it is a good practice to have a data representation with the properties you want the client to access. Returning the user password in the response is not cool. My API has a struct name UserResponse which is responsible for that. The result from invoking the repository function GetUsers is a slice of entity.User. An entity.User object has the password in it. The handler needs to turn each entity.User into a UserResponse. Here is the UserResponse definition

type UserResponse struct {
  entity.User
  Password    bool `json:"-"`
}

If you are wondering why I am creating the Password property again within UserResponse and setting it as a bool, you can learn more about it on JSON and struct composition in Go.

Here is the code on the handler that creates a slice of UserResponse.

// ... service definition, user response and so on
func (s service) Query(offset int, limit int) ([]User, error) {
	users, err := s.repo.GetUsers(offset, limit)
	if err != nil {
		return nil, err
	}

	var result []UserResponse

	for _, u := range users {
		result = append(result, UserResponse{User: &u})
	}

	return result, nil
}

That looks great but it does not work properly because I am assuming here that u from _, u :: ranage users { } is a variable containing a different user on each iteration. That assumption is correct. Indeed for each iteration I get a different user. The problem is how I use that variable u when appending it to the result slice. After I finished writing this code and restarted the server I hit that endpoint and got a list back with three users, which were exactly the number of users I had in the users table. To my surprise, unfortunately, the list had the same user three times, which was the last user. I had no idea what was going on and tried different approaches to fix this but none helped until I figured out the real issue.

When iterating slices, you assign each element (a user object in my case) to the loop iterator variable. That loop variable u is the same for the whole loop. It will be the same when the first user is assigned to it as well as when the last user is assigned to it. Be being the same variable I mean it has the same memory address. Each iteration of the loop you assign a user to that address. On the first iteration you have the first user assigned to u. So u is how you access the first user. The u address is 0x40e020. However, on the next loop iteration u gets assigned the second user. Now you no longer can access the first user because u points to the second one. On the first iteration that user was appended to the result slice doing this result = append(result, User{User: &u}). That does not what it is expected to do because &u is keeping reference to the current user. What gets appended to the slice is the u address. The u refers to the first user in the first iteration. On the second iteration the same happens, this time for the second user. u is appended again to the slice. By the end of the second iteration the slice contains to references, right? That is partially right. What I mean by partially is though the slice has two elements, those two elements points to the same location, which the u location. So you get the same address for the first and second element in the slice. When showing up that data to the client you end up displaying the same user no matter how many users you have to return. That user that is repeated on the response is always the last user in the users slice because on the last iteration over users u got assigned the last user and since all elements in the result slice have the same address.

Here is the solution I was able to figure out after reading that the real issue lin above.

for _, u := range users {
  newU := u
  result = append(result, UserResponse{User: newU})
}

To keep track of the current user a new variable newU is created and the current user is assigned to it. Since := is being used a new address is generated and that new one is appended to the slice. Now each user has its own reference.