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

时间:2017-02-08 07:57:25

标签: go lambda interface type-assertion

我想创建一个可以作为http的HandleFunc的函数,但也可以使用另一个编写器调用。

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

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

http.HandleFunc("/", doit)

但不是:

  

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

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

这样的功能可能吗?

1 个答案:

答案 0 :(得分:4)

Spec: Function types:

  

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

您的doit()函数不符合http.HandlerFunc条件,因为参数类型不匹配。类型io.Writerhttp.ResponseWriter是两种完全不同的类型,因此采用这些类型的函数类型也不同。

使用匿名函数值

但是,由于接口类型io.Writer的{​​{3}}是http.ResponseWriter方法集的子集,因此后一种类型的值可以是method set前一种变量。

您可以将其包装在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类型

另一种选择是定义您自己的函数类型,您可以附加一个简单的方法来实现assigned(即ServeHTTP()),并使用简单类型http.Handler您可以将您的功能注册为处理程序:

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