Golang:Gin遍历map注册路由仅调用同一handler问题求解
问题成因
这是Go语言循环变量捕获的经典闭包问题:
- for range 循环中声明的迭代变量
k、v是全局复用的,所有迭代共享同一块内存地址,每次循环只会更新这两个变量的值 - 你在循环内定义的Gin处理函数是闭包,直接引用了外部的
k、v变量,不会捕获当前迭代的瞬时值,只会绑定变量本身 - 等到路由注册完成、服务启动接收请求时,循环已经执行完毕,
k、v已经存储了最后一次迭代的取值,因此所有路由的处理逻辑都会调用最后一次迭代的v、传入最后一次迭代的k,表现为所有接口都调用同一个处理函数。
你看到的Gin debug日志中两个路由都指向main.main.func1也印证了这一点:所有路由注册的都是同一个匿名闭包实例。
修复方案
只需要在循环内每次迭代时,将当前的k、v赋值给循环内部的局部变量,让闭包捕获每次迭代独立的局部变量即可,修改后的循环代码如下:
for k, v := range funcs { // 新增局部变量赋值,每次迭代生成独立的k、v副本 k, v := k, v server.GET(k, func(ctx *gin.Context) { v(k) }) }
也可以通过构造闭包参数传值的方式实现,效果完全一致:
for k, v := range funcs { server.GET(k, func(k string, v func(string)) gin.HandlerFunc { return func(ctx *gin.Context) { v(k) } }(k, v)) }
修改完成后重新运行,请求对应路径就会调用匹配的处理函数。
内容的提问来源于stack exchange,提问作者anwerj
相关产品推荐
相关产品推荐

