noloopclosure
noloopclosure
is a linter that disallow reference capture of loop variable inside of a closure.
This linter can prevent bugs introduced by a very popular gotcha in Go by disallowing implicit reference capture when creating closure inside a loop.
Installation
go install github.com/fatanugraha/noloopclosure/cmd/noloopclosure@latest
go vet
's loopclosure
Difference with loopclosure
will only complain if the captured loop variable is inside of a function closure that preceded by go
and defer
keyword and is the last statement in the loop's block (reference).
This linter complain each time it found any captured loop variable inside a function closure. This linter is helpful if you have utilities that abstracts the go
behavior, for example:
func main() {
for i := 0; i < 10; i++ {
runInGoroutine(func() { fmt.Println(i) })
}
}
func runInGoroutine(f func()) {
go f()
}
will pass the go vet
's check while fails the noloopclosure
check.
It's generally a good idea (unless every bit of performance matters) to extract the function creation part inside your loop so that you don't accidentally capture the reference and cause unwanted bugs. For example, code above can be re-written as:
func main() {
for i := 0; i < 10; i++ {
runInGoroutine(newIntPrinter(i))
}
}
func newIntPrinter(i int) func() {
func() { fmt.Println(i) }
}
func runInGoroutine(f func()) {
go f()
}