使用接受 io.Writer 作为 HandleFunc 的函数

And*_*eKR 2 lambda interface go type-assertion

我想制作一个可以作为 HandleFunc 的函数,http但也可以被其他作者调用。

由于http.ResponseWriter实现io.Writer和我的函数不需要设置 HTTP 标头,我认为这可能是可能的:

func doit(w io.Writer, r *http.Request) {
  w.Write([]byte("Hello"))
}

http.HandleFunc("/", doit)
Run Code Online (Sandbox Code Playgroud)

但不是:

不能在 http.HandleFunc 的参数中使用 doit (type func(io.Writer, *http.Request)) 作为类型 func(http.ResponseWriter, *http.Request)

这是有道理的,因为它需要类型断言才能使 io.Writer 与预期的 http.ResponseWriter 兼容。

函数可以实现类似的功能吗?

icz*_*cza 5

规格: 功能类型:

函数类型表示具有相同参数和结果类型的所有函数的集合。

您的doit()函数不符合 an 的条件,http.HandlerFunc因为参数类型不匹配。的类型io.Writerhttp.ResponseWriter2种完全不同的类型,所以服用这些类型的功能的类型也不同。

使用匿名函数值

然而,由于该方法集的接口类型的io.Writer是设置的方法的一个子集http.ResponseWriter,后者类型的值可以被分配给前一类型的变量。

您可以将它包装在一个匿名函数中,http.HandlerFunc该函数可以简单地调用doit(),然后您可以将它用作http.HandlerFunc

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    doit(w, r)
})
Run Code Online (Sandbox Code Playgroud)

带有辅助函数的匿名函数值

如果您多次需要此功能,您可以创建一个辅助函数来生成http.HandlerFunc函数值:

func wrap(f func(w io.Writer, r *http.Request)) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        f(w, r)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用它很简单:

http.HandleFunc("/", wrap(doit))
Run Code Online (Sandbox Code Playgroud)

带自定义Handler类型

另一种选择是定义您自己的函数类型,您可以附加一个简单的方法来实现http.Handler(即ServeHTTP()),这样通过简单的类型转换,您就可以将您的函数注册为处理程序:

type SimpleHandler func(io.Writer, *http.Request)

func (sh SimpleHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    sh(w, r)
}
Run Code Online (Sandbox Code Playgroud)

使用它:

http.Handle("/", SimpleHandler(doit))
Run Code Online (Sandbox Code Playgroud)

请注意,表达式SimpleHandler(doit)只是一种类型转换,而不是函数调用。所以这里没有在后台创建新的值或匿名函数,这个解决方案是最有效的。