packagemainimport("io""net/http""log")// hello world, the web serverfuncHelloServer(whttp.ResponseWriter,req*http.Request){io.WriteString(w,"hello, world!\n")}funcmain(){http.HandleFunc("/hello",HelloServer)err:=http.ListenAndServe(":12345",nil)iferr!=nil{log.Fatal("ListenAndServe: ",err)}}
typeappHandlerfunc(http.ResponseWriter,*http.Request)(int,error)// Our appHandler type will now satisify http.Handler func(fnappHandler)ServeHTTP(whttp.ResponseWriter,r*http.Request){ifstatus,err:=fn(w,r);err!=nil{// We could also log our errors centrally:// i.e. log.Printf("HTTP %d: %v", err)switchstatus{// We can have cases as granular as we like, if we wanted to// return custom errors for specific status codes.casehttp.StatusNotFound:notFound(w,r)casehttp.StatusInternalServerError:http.Error(w,http.StatusText(http.StatusInternalServerError),http.StatusInternalServerError)default:// Catch any other errors we haven't explicitly handledhttp.Error(w,http.StatusText(http.StatusInternalServerError),http.StatusInternalServerError)}}funcmyHandler(whttp.ResponseWriter,r*http.Request)(int,error){session,err:=store.Get(r,"myapp")iferr!=nil{// Much better!returnhttp.StatusInternalServerError,err}post:=Post{ID:id}exists,err:=db.GetPost(&post)iferr!=nil{returnhttp.StatusInternalServerError,err}// We can shortcut this: since renderTemplate returns `error`,// our ServeHTTP method will return a HTTP 500 instead and won't // attempt to write a broken template out with a HTTP 200 status.// (see the postscript for how renderTemplate is implemented)// If it doesn't return an error, things will go as planned.returnhttp.StatusOK,renderTemplate(w,"post.tmpl",data)}funcmain(){// Cast myHandler to an appHandlerhttp.Handle("/",appHandler(myHandler))http.ListenAndServe(":8000",nil)}
Function types in Go can also have methods. It’s hard to see, at first, why this would be useful.
There are two side effects to the fact that function types can have methods in Go:
firstly, since any type that can have methods can satisfy an interface, function types in Go can also be boxed into valid interface types.
Secondly, since methods in Go can have either pointer or value receivers, we can use methods on function pointers to switch the function being pointed to in the method’s calling context.