A single function (in your example, func ServeHTTP, doesn't satisfy any interfaces.
The reason to attach a method to a function type is therefore to satisfy an interface.
What value is there in this? The same value in having any other type implement an interface. Let's look at the http.Handler interface, since you brought that up.
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
You can implement this interface with, for example, a struct:
type myHanlder struct {
/* some fields */
}
func (s *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
/* do things */
}
You could also satisfy it with some simpler type. Say, a string:
type myStringHandler string
func (h myStringHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
_, _ = fmt.Fprintf(w, "The string is: %s", h)
}
But if you want to just implement the function directly, as with:
func myHandler(w http.ResponseWriter, r *http.Request) {
/* do things */
}
This doesn't satisfy the interface. So we need to create a type that matches the function signature, and provides the interface methods. That's what http.HandlerFunc does:
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
If the question is: Why did the authors of the standard library decide to make ServerHTTP an interface, rather than a function type, without searching old mailing list archives for clues, only speculation is possible, which is really off-topic here, but here's a small stab at it:
- Interfaces are easier to work with, because they can be easily expanded/embedded. That is, I could implement a struct that satisfies both the
http.Handler interface, and some other interface. This would be more cumbersome (though not strictly impossible) if http.Handler wasn't an interface.
- It's idiomatic. Using an interface for "duck typing" just fits with the Go way of doing things. Maybe that's a bit of a tautology, since the reason it fits with Go is becuase it's done this way.
- If you ever have a complex handler, which maybe tracks its own state, using a struct is the natural solution, and exposing it as an interface is more natural than a closure (which would be required if this were implemented as a function type).
As a thought experiment, just imagine if the io.Reader interface where instead a function type:
type Reader func(p []byte) (n int, err error)
I think it's pretty easy to see that madness would ensue all over the place.