I'm learning Go by writing an app for GAE, and this is signature of a handler function:
func handle(w http.ResponseWriter, r *http.Request) {}
I'm pointer newbie here, so why is the Request
object a pointer, but the ResponseWriter
not? Is there any need to have it this way or is this just to make some kind of advanced pointer based code possible?
What you get for w
is a pointer to the non exported type http.response
but as ResponseWriter
is an interface, that's not visible.
From server.go :
type ResponseWriter interface {
...
}
On the other hand, r
is a pointer to a concrete struct, hence the need to precise it explicitely :
From request.go :
type Request struct {
...
}
The http.ResponseWriter
is an interface, and the existing types implementing this interface are pointers. That means there's no need to use a pointer to this interface, as it's already "backed" by a pointer. This concept is describe a bit by one of the go develpers here Although a type implementing http.ResponseWriter didn't need to be a pointer, it would not be practical, at least not within the go http server.
http.Request
is not an interface, it's just a struct, and since we want to change this struct and have the web server see those changes, it has to be a pointer. If it was just a struct value, we would just modify a copy of it that the web server calling our code could not see.
The reason why it’s a pointer to Request is simple: changes to Request by the handler need to be visible to the server, so we’re only passing it by reference instead of by value.
If you dig into the net/http library code, you’ll find that ResponseWriter is an interface to a nonexported struct response, and we’re passing the struct by reference (we’re passing in a pointer to response) and not by value. ResponseWriter is an interface that a handler uses to create an HTTP response. The actual struct backing up ResponseWriter is the nonexported struct http.response. Because it’s nonexported, you can’t use it directly; you can only use it through the ResponseWriter interface.
In other words, both the parameters are passed in by reference; it’s just that the method signature takes a ResponseWriter that’s an interface to a pointer to a struct, so it looks as if it’s passed in by value.
I think that the main reason for the Request
object to be passed as a pointer is the Body
field. For a given HTTP request, the body can only we read once. If the Request
object was cloned, as it would be if it wasn't passed as a pointer, we would have two objects with different information about how much has been read from the body.