Today while working on my side project I have encountered interesting issue and despite I was able to overcome it I have realised that I might be missing some import concepts about Go.
Let me share example code to demostrate the issue I am referring to:
```go
package main
import (
"net/http"
"
github.com/gorilla/mux"
)
func main() {
// We can pass GorillaRouter as Router, because it implement required methods
_ = ServerHandler{
router: NewGorillaRouter(),
}
// We can not pass FailingRouter as Router, because of:
// cannot use FailingRouter{} (value of type FailingRouter) as type Router in struct literal:
// FailingRouter does not implement Router (wrong type for HandleFunc method)
// have HandleFunc(path string, handler func(http.ResponseWriter, *http.Request)) *FailingRoute
// want HandleFunc(path string, handler func(http.ResponseWriter, *http.Request)) Route
_ = ServerHandler{
router: FailingRouter{},
}
}
type ServerHandler struct {
router Router
}
type Router interface {
HandleFunc(path string, handler func(http.ResponseWriter, *http.Request)) Route
}
type Route interface {
Methods(methods ...string) Route
}
func NewGorillaRouter() *GorillaRouter {
return &GorillaRouter{
router: mux.NewRouter(),
}
}
type GorillaRouter struct {
router *mux.Router
}
func (gr *GorillaRouter) HandleFunc(path string, handler func(http.ResponseWriter, *http.Request)) Route {
return &GorillaRoute{
route: gr.router.HandleFunc(path, handler),
}
}
type GorillaRoute struct {
route *mux.Route
}
func (r *GorillaRoute) Methods(methods ...string) Route {
r.route = r.route.Methods(methods...)
return r
}
type FailingRouter struct{}
func (fr *FailingRouter) HandleFunc(path string, handler func(http.ResponseWriter, *http.Request)) *FailingRoute {
return &FailingRoute{}
}
type FailingRoute struct{}
func (r *FailingRoute) Methods(methods ...string) *FailingRoute {
return r
}
```
For convienence you can find soure code from above and run it here:
https://go.dev/play/p/M6N48FeegNDNow when code and context is clear question is following: why in `FailingRouter` assignment compiler is not happy while in `GorillaRouter` it is happy?
Or to rephrase, why assigning concrete implementation to a parameter of interface type is accepted:
```go
type ServerHandler struct {
router Router // assigning GorillaRouter to router is accepted
}
```
but vice versa is not and throws an error:
```go
HandleFunc(path string, handler func(http.ResponseWriter, *http.Request)) *FailingRoute // returning concrete that implements Router is not allowed
```
P.S. Sorry about the title, I am still not sure is it right for this problem description.