I'm confused about this bit of code from the HTTP package:
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
Why does the ServeHTTP
method have the exact same signature as it's type - what's the point?
Testing, I discovered that if I pass a random function (foo
) to the HandlerFunc
:
var bar = HandlerFunc(foo)
bar
becomes an instance of HandlerFunc
with foo
as its ServeHTTP
method. Now I'm really confused about how on earth this works.
If I have more than one methods on a type, how do I know which one is going to be attached to the new instance and with what name or order?
This approach allows you to use a function in a context that's expecting a Handler
.
What happens is, there's a Handler
interface:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
and various functions are declared to accept parameters that are declared to belong to this interface — for example:
func TimeoutHandler(h Handler, ns int64, msg string) Handler {
f := func() <-chan int64 {
return time.After(ns)
}
return &timeoutHandler{h, f, msg}
}
What this means is that when you invoke such a function, you have to pass in an object belonging to a type that satisfies this interface, which is to say, a type that has a ServeHTTP
method with the appropriate signature. (In Go, unlike some languages, a type doesn't need to explicitly implement an interface, it just needs to have the methods specified by the interface.)
So, the code-snippet that you quote:
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
creates a type HandlerFunc
that's based on func(ResponseWriter, *Request)
, but augments the type with a method called ServeHTTP
with an appropriate signature, so that it satisfies the Handler
interface. This ServeHTTP
method just calls the function itself. So, if f
is a function with the right signature, you could write something like this:
var h HandlerFunc = f // h == f, but converted to a HandlerFunc
// so it satisfies the Handler interface.
TimeoutHandler(h, 1000000, "timed out")
To clarify a few things about this:
Testing, I discovered that if I pass a random function (
foo
) to theHandlerFunc
:var bar = HandlerFunc(foo)
bar
becomes an instance ofHandlerFunc
withfoo
as itsServeHTTP
method. Now I'm really confused about how on earth this works.
Firstly, it's more correct to say that you've converted a random function foo
to type HandlerFunc
, rather than that you've passed the function to HandlerFunc
as though HandlerFunc
were a function. (The HandlerFunc(foo)
notation is a typecast; you could just as well write var bar HandlerFunc = foo
and let the conversion happen implicitly.)
Secondly, it's more correct to say that bar
has a ServeHTTP
method that invokes foo
, than that foo
itself actually is the ServeHTTP
method.
Does that make sense?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With