tags:

views:

108

answers:

2

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?

+1  A: 

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.

Dan Lorenc
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.
Suppressingfire
+4  A: 

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.

Kinopiko
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.http://golang.org/doc/effective_go.html#conversions
mbarkhau