使用循环切片/映射的范围注册多个路由 [英] Register multiple routes using range for loop slices/map

查看:87
本文介绍了使用循环切片/映射的范围注册多个路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑一下,我有一段字符串路径:

Consider I have slice of string paths:

paths := []string{"/path0", "/path1", "/path2" /*... "/path-n"*/ }
// where n is the last path

使用软件包 net / http ,我想使用 for 带范围子句的循环。这就是我的操作方法:

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

编辑:基本上,提问者使用以下代码:

for _, path := range paths {
    http.HandleFunc(path, func(w http.ResponseWriter, req *http.Request) {
        fmt.Fprintf(w, path)
    })
}

但是我最终得到了相同的输出,这是slice的最后一个元素,所以当我去 / path1 ,输出是 / path-n 。与其他元素的行为相同,请始终打印 / path-n

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)

输出正确。

这是怎么回事,我错过了什么吗?我需要 for 循环来进行路径切片或地图给出的注册,所以我无法执行第二个代码。

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:

for _, path := range paths {
    http.HandleFunc(path, func(w http.ResponseWriter, req *http.Request) {
        fmt.Fprintf(w, path)
    })
}

您使用了函数文字,即闭包作为要注册的处理函数。闭包捕获它们所引用的上下文,在您的情况下为 path 循环变量。

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.

但是只有一个 path 循环变量,其值在循环的每次迭代中都会被覆盖,并且其最终值将是最后一个路径。规范中的相关部分:对于带有 range 子句的语句

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 with range clause:


迭代变量可以由 range子句使用短变量声明:= )。在这种情况下,它们的类型设置为相应迭代值的类型,并且它们的 scope 是一个块 for声明的内容; 它们在每次迭代中都会重复使用。如果迭代变量在 for语句之外声明,则执行后它们的值将是上一次迭代的值。

The iteration variables may be declared by the "range" clause using a form of short variable declaration (:=). In this case their types are set to the types of the respective iteration values and their scope is the block of the "for" statement; they are re-used in each iteration. If the iteration variables are declared outside the "for" statement, after execution their values will be those of the last iteration.

for 循环完成,并且您开始发出请求,每个已注册的处理程序函数都将发回该单个 path 的值。变量。这就是为什么看到所有请求的路径都返回最后一条路径的原因。

Once the for loop is finished, and you start making requests, each registered handler function will send back the value of this single path 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:

for _, path := range paths {
    path2 := path
    http.HandleFunc(path2, func(w http.ResponseWriter, req *http.Request) {
        fmt.Fprintf(w, path2)
    })
}

这里发生的是,我们使用了短变量在每次迭代中声明以创建一个 new 变量,并使用 path 循环变量的值进行初始化。然后,我们注册的处理程序函数将引用这个新变量,该变量仅对一个注册路径唯一。

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.

另一种同样好的解决方案是使用带有参数的匿名函数传递 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:

for _, path := range paths {
    func(p string) {
        http.HandleFunc(p, func(w http.ResponseWriter, req *http.Request) {
            fmt.Fprintf(w, p)
        })
    }(path)
}

这里发生的是我们调用一个匿名函数,传递了当前的 path 值,它仅使用此匿名函数的参数注册处理程序函数(并且为每个调用分配了一个新的,不同的局部变量)。

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).

这篇关于使用循环切片/映射的范围注册多个路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆