Consider I have slice of string paths:
paths := []string{"/path0", "/path1", "/path2" /*... "/path-n"*/ }
// where n is the last path
Using package net/http
, I want to register handler for this path using for
loop with range clause. This is how I do this:
for _, path := range paths {
http.HandleFunc(path, handler)
}
// in this case every handler is print the path to the console or to the browser
But I ended up with same output which is the last element of slice, so when I go to /path1
, the output is /path-n
. Same behavior with other element, always print /path-n
.
But if I use this:
http.HandleFunc(paths[0], handler)
http.HandleFunc(paths[1], handler)
http.HandleFunc(paths[2], handler)
// ...
http.HandleFunc(paths[n], handler)
The output is correct.
What's going on, did I miss something? I need for
loop for registration given by slice of paths or map, so I can't do the second code.
Can you give me the alternative to accomplished this task?
So the problem was that you actually used this code:
You used a function literal, a closure as the handler function to register. Closures capture the context they refer to, in your case the
path
loop variable.But there is only a single
path
loop variable, its value is overwritten in each iterations of the loop, and its final value will be the last path. Relevant section from the spec: For statements withrange
clause:Once the
for
loop is finished, and you start making requests, each registered handler function will send back the value of this singlepath
variable. That's why you see the last path returned for all requested paths.Solution is easy: create a new variable in each iteration, and use that in the handler function:
What happens here is that we use a short variable declaration in each iteration to create a new variable, initialized with the value of the
path
loop variable. And the handler function we register will refer to this new variable, unique only to one registered path.Another, equally good solution is to use an anonymous function with a parameter to pass the
path
string. Might be harder to understand though:What happens here is that we call an anonymous function, passing the current
path
value to it, and it registers the handler function, using only the parameter of this anonymous function (and there's a new, distinct local variable allocated for each call).