How to solve loop variable captured by func literal in anonymous Go function

Published: 2024-05-14 | Updated: 2024-06-27

In my process of learning how to code a Golang web crawler I ran into an unexpected warning:

loop variable url captured by func literal / loopclosure(default)
var url string

The code seemed pretty straightforward.

// The crawler makes concurrent page requests. This is 
// the worker where that happens
func processPage(url) {
// go get the page and do work with it...
}

wg := sync.WaitGroup{}
  for _, url := range urls {
    wg.Add(1)
    go func() {
      defer wg.Done()
      processPage(url)
    }()
  }
wg.Wait()

It took me a minute to realize Go was warning me that I was making my anonymous function work harder than it should to gain access to the url variable it needed to kick off the worker function.

Parenthetically, this is one of the ways Go is just a bit more eloquent than, say, PHP where you pass these args via the use keyword.

The solution was to pass the url variable into the anonymous function like so:

// The crawler makes concurrent page requests. This is 
// the worker where that happens
func processPage(url) {
// go get the page and do work with it...
}

wg := sync.WaitGroup{}
  for _, url := range urls {
    wg.Add(1)
  // let's have our anonymous function take an arg
    go func(url string) {
      defer wg.Done()
   // and use that arg here
      processPage(url)
   // we call the anonymous function with the arg
    }(url)
  }
wg.Wait()

…and just like that! No more warnings about loop variable url captured by func literal