Why does net/http declare Handler as a one-method interface and also provide HandlerFunc?
answer
- methods are not limited to struct types
- the receiver is the function itself
- a conversion, not a call
- the body is one line: f(w, r)
- two methods would kill the trick
basics
~20 sBecause http.Handler requires just ServeHTTP, a plain function can implement it: http.HandlerFunc is a named function type with a ServeHTTP method that calls itself. Keeping an interface at one method is what makes such a function adapter possible.
solid answer
~40 s`http.Handler` requires a single method, `ServeHTTP(ResponseWriter, *Request)`. In Go a method can be declared on any named type defined in the same package, including a function type, so `net/http` defines `type HandlerFunc func(ResponseWriter, *Request)` and gives it a `ServeHTTP` method whose whole body is `f(w, r)`. Writing `http.HandlerFunc(myFunc)` is a type conversion, not a call: it produces a value that satisfies the interface. That is why middleware in Go composes as `func(http.Handler) http.Handler` and why handlers can be closures rather than structs. The trick only works at one method -- a two-method interface cannot be satisfied by a bare function, so callers would be pushed back into declaring a type. It is the strongest practical argument for keeping designed interfaces small.
code
go · 6 linestype HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}go deeper
Know that a Go handler can be a plain function because http.HandlerFunc converts it into something with a ServeHTTP method, and that http.HandleFunc does that conversion when registering a route.
Explain the mechanism: a method may be declared on any defined type in the package, including a function type, and the adapter's ServeHTTP body just calls the receiver.
Draw the design lesson in review: keep a capability interface at one method so closures can satisfy it, and ship the matching Func adapter rather than forcing every caller to declare a type.
Decide the encoding at the package boundary. A one-method interface plus a Func adapter keeps a callback seam maximally implementable, while a multi-method interface commits every consumer to declaring and maintaining a type.
## The two declarations `net/http` exports both of these: - `type Handler interface { ServeHTTP(ResponseWriter, *Request) }` - `type HandlerFunc func(ResponseWriter, *Request)`, with the method `func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) }` The second is an *adapter*: it lets an ordinary function be used wherever the interface is required. ## The language rule that makes it work Go lets you declare a method on any *defined* type whose declaration lives in the same package -- not only structs. A function type is a perfectly good defined type, so `HandlerFunc` can carry methods. Its `ServeHTTP` has a receiver that *is* the function, and the body simply calls it. So `http.HandlerFunc(myFunc)` is a conversion between two types with the same underlying type `func(http.ResponseWriter, *http.Request)`. It allocates no wrapper struct and runs nothing; it just changes the static type so the method set now contains `ServeHTTP`. The result satisfies `http.Handler`, and `http.HandleFunc` is the convenience wrapper that does the conversion for you when registering a route. ## Why the interface has to be small for this to exist A function value can supply exactly one behaviour. If `Handler` had required `ServeHTTP` plus, say, `Shutdown` and `Name`, no function type could satisfy it -- every handler would need a struct with three methods, closures could not be handlers, and middleware would stop being a one-line wrapper. The adapter idiom is available *only* to one-method interfaces, which is why the standard library keeps so many of its interfaces at exactly one method: `io.Reader`, `io.Writer`, `fmt.Stringer`, `sort.Interface` being the notable multi-method exception. The same pattern appears elsewhere with the same naming convention: `http.HandlerFunc` for `http.Handler`, and in general `XxxFunc` for a one-method `Xxx`. When you design your own one-method interface, offering the matching `Func` type is cheap and doubles the ways it can be satisfied. ## Where it pays off: middleware Because both the input and the output of a middleware are `http.Handler`, middleware composes by plain function application, and the returned handler is normally a closure converted with `http.HandlerFunc`. That closure captures whatever the middleware needs -- a header name, a limit, a clock -- without declaring a struct or a constructor. A chain is then just nested calls, and each layer is independently testable because it accepts the interface. ## Choosing between the two encodings when you design If a caller supplies one piece of behaviour with no state to configure, a one-method interface plus a `Func` adapter is the most flexible shape: implementers may use either a struct or a function. If the caller genuinely supplies several related behaviours that share state, an interface with two methods is honest; more than that and you are usually describing an object, not a capability, and callers will feel the weight of it in every fake they write. A subtlety worth knowing: a value of type `http.HandlerFunc` is comparable to `nil` but two function values are otherwise not comparable, so an interface holding a `HandlerFunc` cannot be compared for equality with another such interface value at run time -- the comparison panics. That rarely matters in handler code, but it is a real difference between the function encoding and a struct encoding. ## What to remember One method is a magic number in Go interface design. At one method, the interface can be satisfied by a function through a named function type with the method attached; at two or more, only a declared type will do. Design the small interface first, and add the `Func` adapter beside it.
- Is http.HandlerFunc(myFunc) calling the function?No, it is a type conversion. `HandlerFunc` and the function literal share the same underlying type, so the conversion only changes the static type; the resulting value now has a `ServeHTTP` method and therefore satisfies `http.Handler`. The function body runs later, when something calls `ServeHTTP`.
- Could the same adapter trick satisfy a two-method interface?Not with a bare function. A function value can carry one behaviour, so a second required method has nowhere to come from; implementers would need a declared struct holding both. That constraint is a good argument for keeping a designed interface at one method whenever a caller is really supplying one behaviour.
- When you export a one-method interface of your own, what should you ship beside it?A matching `XxxFunc` named function type with the method attached, following the standard library's convention. It costs a few lines, lets callers pass closures instead of declaring types, and does not widen the interface, so nothing extra is imposed on implementers.
It is an adapter plug: the socket accepts one shape, and the adapter lets a bare function present that shape without being rebuilt as an object.
saying these in an interview costs you the question
- Thinks http.HandlerFunc(f) invokes f immediately
- Believes methods can only be declared on struct types
- Says HandlerFunc wraps the function in a hidden struct
- Assumes any interface can be satisfied by a function
- Confuses http.HandlerFunc the type with http.HandleFunc the registration call