为了账号安全,请及时绑定邮箱和手机立即绑定

在golang中将对象从一个包传递到下一个包

在golang中将对象从一个包传递到下一个包

Go
互换的青春 2022-07-11 16:32:40
来自 github,https://github.com/CyCoreSystems/ari/blob/master/_examples/stasisStart/main.go我正在查看下面的启动和对象被保存到 cl 并稍后用于创建 handlefun .. 所有在同一个主体中.. 如果我想打破它并将 handlefunc 放在另一个包中,我怎样才能将 cl 传递给它?cl, err := native.Connect(&native.Options{        Application:  "test",        Username:     "asterisk",        Password:     "abc123",        URL:          "http://localhost:8088/ari",        WebsocketURL: "ws://localhost:8088/ari/events",    })后来,这通过http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {        // make call        log.Info("Make sample call")        h, err := createCall(cl)        if err != nil {            log.Error("Failed to create call", "error", err)            w.WriteHeader(http.StatusBadGateway)            w.Write([]byte("Failed to create call: " + err.Error()))            return        }        w.WriteHeader(http.StatusOK)        w.Write([]byte(h.ID()))    }))
查看完整描述

2 回答

?
噜噜哒

TA贡献1784条经验 获得超7个赞

如何cl“传递给”处理函数

啊,好的,我将做一个纯粹的猜测,并建议您被一小段代码中混合的太多概念所绊倒。


对此的第二个论点http.Handle()是所谓的“函数文字”——“当场”定义函数,而不是“以正常方式”定义它func some_name(list_of_args) body。Go 中的函数字面量是“闭包”,这意味着它们从可用的外部词法范围“捕获”任何变量,它们的主体通过它们的名称来引用它们。您的示例中的函数文字引用cl了该变量,因此它“关闭”了该变量。


我们可以“解包”该代码以使其看起来更容易理解:


cl, err := native.Connect(...)


handler := func(w http.ResponseWriter, r *http.Request) {

  h, err := createCall(cl)

  ...

}


http.Handle("/", http.HandlerFunc(handler))

现在看起来更明智了吗?


分配给变量handler的任何内容都是关闭变量的函数值cl。


你能做些什么呢?

我们可以尝试将其重写为更简单:


cl, err := native.Connect(...)


func handler(w http.ResponseWriter, r *http.Request) {

  h, err := createCall(cl) // Oops, this won't compile

  ...

}


http.Handle("/", http.HandlerFunc(handler))

但是这段代码不会编译,因为常规函数不能引用包含函数定义的词法范围中的变量(让我们不要离题)。


那么,你能做些什么呢?


您不能只是将另一个参数添加到参数列表中,handle因为它必须具有特定的签名,但是让我们想一想,当您希望函数对附加net/http.HandlerFunc的某个状态进行操作时,您通常会做什么? 对,您将函数转换为某种数据类型的方法。


所以,让我们这样做:


type myHander struct {

  cl native.Client // I have no idea which type native.Connect returns...

}


func (*mh myHandler) handle(w http.ResponseWriter, r *http.Request) {

  h, err := createCall(mh.cl)

  ...

}

我们现在可以将它传递给设置内容的代码:


mh := myHandler{

  cl: cl,

}

http.Handle("/", http.HandlerFunc(mh.handle))

更好的方法

但是如果我们使用 RTFM(提示!),我们可以做得更好:文档net/http.HandlerFunc说:


该HandlerFunc类型是一个适配器,允许将普通函数用作 HTTP 处理程序。


因此,如果我们浏览文档以查看“HTTP 处理程序”是什么,我们会得出net/http.Handler哪个是接口类型,并且该接口可以由任何具有方法的数据类型来满足ServeHTTP(http.ResponseWriter, *http.Request)。

你看到与 有什么相似之处myHandler.handle吗?正确的。


所以我们的类型可以变成


type myHander struct {

  cl native.Client // I have no idea which type native.Connect returns...

}


func (*mh myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

  h, err := createCall(mh.cl)

  ...

}

然后我们可以做


mh := myHandler{

  cl: cl,

}

http.Handle("/", &mh)


查看完整回答
反对 回复 2022-07-11
?
慕尼黑的夜晚无繁华

TA贡献1864条经验 获得超6个赞

您可以将处理程序代码提取到单独的工厂函数中:


func MakeHandler(cl *Conn) http.Handler {

    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

        // make call

        log.Info("Make sample call")

        h, err := createCall(cl)

        if err != nil {

            log.Error("Failed to create call", "error", err)

            w.WriteHeader(http.StatusBadGateway)

            w.Write([]byte("Failed to create call: " + err.Error()))

            return

        }


        w.WriteHeader(http.StatusOK)

        w.Write([]byte(h.ID()))

    })  

}

然后在您的原始范围内使用它。


http.Handle("/", otherpkg.MakeHandler(cl))


查看完整回答
反对 回复 2022-07-11
  • 2 回答
  • 0 关注
  • 91 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信