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

3
我希望创建一个函数,可以作为HandleFunc用于http,也可以使用另一个writer进行调用。
由于http.ResponseWriter实现了io.Writer,而我的函数不需要设置HTTP头,因此我认为这是可能的:
func doit(w io.Writer, r *http.Request) {
  w.Write([]byte("Hello"))
}

http.HandleFunc("/", doit)

但是不行:

无法使用doit(类型为func(io.Writer,*http.Request))作为http.HandleFunc中参数类型为func(http.ResponseWriter,*http.Request)的函数

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

函数是否可以实现类似功能?

1个回答

6

规范: 函数类型:

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

你的doit()函数不符合http.HandlerFunc的要求,因为参数类型不匹配。类型io.Writerhttp.ResponseWriter是完全不同的类型,所以采用这些类型的函数类型也是不同的。

使用匿名函数值

然而,由于接口类型io.Writerset方法http.ResponseWriter方法集的子集,因此后者类型的值可以分配给前者类型的变量。
您可以将其包装在类型为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(即ServeHTTP()),这样通过简单的类型转换,您可以将您的函数注册为处理程序:

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)仅仅是一种类型转换,而不是函数调用。因此,在后台没有创建新的值或匿名函数,这个解决方案是最有效的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接