【问题标题】:Why http.HandlerFunc always returns the same random number为什么 http.HandlerFunc 总是返回相同的随机数
【发布时间】:2020-05-07 21:41:35
【问题描述】:

来自新手 gopher 的问候!

我有以下多路复用路由器设置:

s.router.HandleFunc("/test", s.TestHandler())

s.TestHandler:

func (s *server) TestHandler() http.HandlerFunc {
    rnd := rand.Intn(100)
    response := struct {
        RND int `json:"rnd"`
    }{
        rnd,
    }
    return func(w http.ResponseWriter, r *http.Request) {
        s.respond(w, r, 200, response)
        return
    }
}

辅助方法 s.respond:

func (s *server) respond(w http.ResponseWriter, r *http.Request, code int, data interface{}) {
    w.WriteHeader(code)
    if data != nil {
        json.NewEncoder(w).Encode(data)
    }
}

问题是当我发出 GET /test 时,除非重新启动应用程序,否则我会看到相同的数字。

我确定我做错了什么,如果有人指出我的错,将不胜感激。

【问题讨论】:

  • 正式地:因为你不生成一个“随机”数,所以你生成一个“伪随机”数。这一代数字是确定性的,只有数字的序列看起来(有点)随机。
  • @Volker - 这是真的,但在 OP 的问题中,这是因为他们的 handlerfunc 不包括对rand.Intn 的调用,它包括已经生成的号码。

标签: go gorilla


【解决方案1】:

Function literals

函数字面量是闭包:它们可以引用定义在 一个周边功能。然后这些变量在 周围的函数和函数字面量,它们作为 只要它们可以访问。


TestHandler() 生成一个单个随机值,然后返回一个函数字面量,即一个闭包,它使用这个已经生成的值来每当路由器执行时发送响应。

但是,当调用闭包时,闭包的周边函数不会也没有理由与闭包一起执行。环绕函数仅在它本身被调用时才会执行,例如当您在s.router.HandleFunc("/test", s.TestHandler()) 中注册处理程序时。

因此,在提供的代码中,您的 TestHandler 中的 rand.Intn 函数只被调用一次,而不是像您所相信的那样,每次您向服务器发出请求时都会调用它。

要解决此问题,只需将生成随机值的代码移至以下级别:

func (s *server) TestHandler() http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        rnd := rand.Intn(100)
        response := struct {
            RND int `json:"rnd"`
        }{
            rnd,
        }

        s.respond(w, r, 200, response)
    }
}

【讨论】:

  • 谢谢您,先生!我还必须学习何时使用和何时不使用闭包(目前我的用例还不是 100% 清楚=)
  • @MichaelC 是的,在这种情况下,让TestHandler 返回一个处理程序比让TestHandler 只是成为处理程序没有真正的好处。但是,在某些情况下,您实际上可能想要执行一次 XYZ,然后让返回的闭包重新使用该 XYZ 的结果。跨度>
  • @MichaelC 考虑这个example,在这里你看到模板的解析只完成一次,然后模板被返回的闭包重用,这节省了很多CPU周期如果解析阶段在闭包内,否则会造成不必要的浪费。
  • @MichaelC 许多 Go 处理程序特定的“中间件”也是使用闭包实现的,如果您继续在 Go 中编写 Web 服务器,您很快就会遇到这些。此外,以下链接可能有助于进一步了解如何/何时使用它们:golang.org/doc/articles/wiki/#tmp_12
  • 是的,我将继续编写 web 应用程序,我喜欢它比我偶尔处理的 PHP 更喜欢它。感谢您为我指明了正确的方向,我看到闭包可能会在 Web 应用程序中用于实现一些中间件......
猜你喜欢
  • 1970-01-01
  • 2017-05-20
  • 1970-01-01
  • 2018-09-23
  • 1970-01-01
  • 2010-12-22
  • 2020-04-06
  • 1970-01-01
相关资源
最近更新 更多