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)
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))
- 2 回答
- 0 关注
- 91 浏览
添加回答
举报