22

I want to know what is happening here.

There is the interface for a http handler:

type Handler interface {
    ServeHTTP(*Conn, *Request)
}

This implementation I think I understand.

type Counter int

func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
    fmt.Fprintf(c, "counter = %d\n", ctr);
    ctr++;
}

From my understanding it is that the type "Counter" implements the interface since it has a method that has the required signature. So far so good. Then this example is given:

func notFound(c *Conn, req *Request) {
    c.SetHeader("Content-Type", "text/plain;", "charset=utf-8");
    c.WriteHeader(StatusNotFound);
    c.WriteString("404 page not found\n");
}

// Now we define a type to implement ServeHTTP:
type HandlerFunc func(*Conn, *Request)
func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
    f(c, req) // the receiver's a func; call it
}
// Convert function to attach method, implement the interface:
var Handle404 = HandlerFunc(notFound);

Can somebody elaborate on why or how these various functions fit together?

2 Answers 2

30

This:

type Handler interface {
    ServeHTTP(*Conn, *Request)
}

says that any type which satisfies the Handler interface must have a ServeHTTP method. The above would be inside the package http.

type Counter int

func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
    fmt.Fprintf(c, "counter = %d\n", ctr);
    ctr++;
}

This puts a method on the Counter type which corresponds to ServeHTTP. This is an example which is separate from the following.

From my understanding it is that the type "Counter" implements the interface since it has a method that has the required signature.

That's right.

The following function by itself won't work as a Handler:

func notFound(c *Conn, req *Request) {
    c.SetHeader("Content-Type", "text/plain;", "charset=utf-8");
    c.WriteHeader(StatusNotFound);
    c.WriteString("404 page not found\n");
}

The rest of this stuff is just fitting the above so that it can be a Handler.

In the following, a HandlerFunc is a function which takes two arguments, pointer to Conn and pointer to Request, and returns nothing. In other words, any function which takes these arguments and returns nothing can be a HandlerFunc.

// Now we define a type to implement ServeHTTP:
type HandlerFunc func(*Conn, *Request)

Here ServeHTTP is a method added to the type HandlerFunc:

func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
    f(c, req) // the receiver's a func; call it
}

All it does is to call the function itself (f) with the arguments given.

// Convert function to attach method, implement the interface:
var Handle404 = HandlerFunc(notFound);

In the above line, notFound has been finagled into being acceptable for the interface for Handler by artificially creating a type instance out of the function itself and making the function into the ServeHTTP method for the instance. Now Handle404 can be used with the Handler interface. It's basically a kind of trick.

Sign up to request clarification or add additional context in comments.

2 Comments

Ok I think I get it now, the thing that tripped me up was the conversion of notFound to HandlerFunc. After rereading the conversions section of effective go it is more clear how that can also apply to functions. golang.org/doc/effective_go.html#conversions
Thanks a lot for this answer. I was having a hard time understanding the reason behind all this gymnastics, even got donwvotes on my own SO question on it. Your answer explains it the way it should be done. And word 'trick' explains the 'reason' behind it much better:).
-2

What exactly don't you understand about the second half? It's the same pattern as above. Instead of defining the Counter type as an int, they define a function called notFound. They then create a type of function called HandlerFunc that takes two parameters, a connection and a request. they then create a new method called ServeHTTP, that gets bound to the HandlerFunc type. Handle404 is simply an instance of this class that uses the notFound function.

1 Comment

Yeah, it's typical higher order functional programming. It can be confusing the first time you see it and work your way through the types.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.