我在读到,在 Go 中,函数可以实现接口(interface)(like in this example 或 this example)。
但是让函数实现接口(interface)有什么值(value)呢?
例如,为什么要花时间定义接口(interface)、函数的新类型和方法,如下所示:
type Handler interface {
ServeHTTP(*Conn, *Request)
}
type HandlerFunc func(*Conn, *Request)
func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
f(c, req)
}
当您可以像这样创建一个函数时:
func ServeHTTP(f func(*Conn, *Request), c *Conn, req *Request) {
f(c, req)
}
提前致谢!
单个函数(在您的示例中,func ServeHTTP
,不满足任何接口(interface)。
因此,将方法附加到函数类型的原因是满足接口(interface)。
这有什么值(value)?让任何其他类型实现接口(interface)具有相同的值(value)。让我们看看 http.Handler
接口(interface),因为您已经提出了它。
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
例如,您可以使用结构来实现此接口(interface):
type myHanlder struct {
/* some fields */
}
func (s *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
/* do things */
}
你也可以用一些更简单的类型来满足它。比如说,一个字符串:
type myStringHandler string
func (h myStringHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
_, _ = fmt.Fprintf(w, "The string is: %s", h)
}
但是如果你想直接实现函数,比如:
func myHandler(w http.ResponseWriter, r *http.Request) {
/* do things */
}
这不满足接口(interface)。所以我们需要创建一个匹配函数签名的类型,并提供接口(interface)方法。这就是 http.HandlerFunc
所做的:
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
如果问题是:为什么标准库的作者决定让 ServerHTTP
成为一个接口(interface),而不是一个函数类型,没有搜索旧邮件列表文件的线索,只有猜测是可能的,这在这里确实是题外话,但这里有一个小插曲:
- 接口(interface)更易于使用,因为它们可以轻松扩展/嵌入。也就是说,我可以实现一个同时满足
http.Handler
接口(interface)和其他一些接口(interface)的结构。如果 http.Handler
不是一个接口(interface),这会更麻烦(尽管并非完全不可能)。
- 这是地道的。使用“鸭子打字”界面恰好符合 Go 的做事方式。也许这有点重言式,因为它适合 Go 的原因是因为它是以这种方式完成的。
- 如果您有一个复杂的处理程序,它可能会跟踪自己的状态,那么使用结构是自然的解决方案,并且将其作为接口(interface)公开比闭包更自然(如果将其实现为函数,则需要闭包)类型)。
作为一个思想实验,想象一下如果 io.Reader
接口(interface),而不是函数类型:
type Reader func(p []byte) (n int, err error)
我认为很容易看出到处都会发生疯狂。