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

Use function that accepts io.Writer as HandleFunc

我想创建一个函数,它可以是 http 的 HandleFunc,但也可以被其他作者调用。

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

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

http.HandleFunc("/", doit)

但是没有:

cannot use doit (type func(io.Writer, *http.Request)) as type func(http.ResponseWriter, *http.Request) in argument to http.HandleFunc

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

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

Spec: Function types:

A function type denotes the set of all functions with the same parameter and result types.

你的doit()函数不符合http.HandlerFunc because parameter types do not match. The types io.Writer and http.ResponseWriter是2种完全不同的类型,所以采用这些类型的函数类型也不同。

使用匿名函数值

但是,由于method set of the interface type io.Writer is a subset of the method set of http.ResponseWriter, a value of the latter type can be assigned前的变量类型。

您可以将其包装在类型为 http.HandlerFunc 的匿名函数中,该函数可以简单地调用 doit(),然后您可以将其用作 http.HandlerFunc:

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    doit(w, r)
})

带辅助函数的匿名函数值

如果你多次需要这个,你可以创建一个辅助函数来产生 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)
    }
}

然后使用它就是:

http.HandleFunc("/", wrap(doit))

使用自定义 Handler 类型

另一个选择是定义你自己的函数类型,你可以附加一个简单的方法来实现http.Handler (namely ServeHTTP()), and that way with a simple type conversion你可以将你的函数注册为处理程序:

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

func (sh SimpleHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    sh(w, r)
}

使用它:

http.Handle("/", SimpleHandler(doit))

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