Search code examples
gointerfacecastingtype-assertion

Type assertions with interface embedding in Go


  • I have an interface and it is embedded into multiple structs that form a decorator pattern.
  • Now I have added code to typecast Validator and APIService to the API interface. So that if I add and a function to the interface then I should be able to add it at Validator and APIService.

But this code seems to compile. I should have got a compiler error as I have not implemented Get on Validator If I remove Get from APIService I get an error which says I cant typecast to *APIService to API as get is not implemented.

package main

import "fmt"

type API interface {
  Get()
}
var _ API = (*Validator)(nil)
var _ API = (*APIService)(nil)

type APIService struct {
  id string
}

type Validator struct {
  API
}

type APIRouter struct {
  API
}

func(a *APIService) Get(){
  fmt.Println("Calling Get api on APIService")
}

func NewAPIRouter() *APIRouter{
  return &APIRouter{
    API: &Validator{
      API: &APIService{
      },
    },
  }
}
func main() {
  var api API = NewAPIRouter()
  api.Get()
}

If I compile the above code:

./main
Calling Get api on APIService

But if I comment Get function on APIService i get the below error which is valid:

go build
# main
./main.go:9:5: cannot use (*APIService)(nil) (type *APIService) as type API in assignment:
    *APIService does not implement API (missing Get method)

I should have got a compiler error before as well as I have not implemented Get on Validator If I remove Get from APIService I get an error which says I cant typecast to *APIService to API as get is not implemented.


Solution

  • The type APIService is a struct with a method Get, so it implements API interface.

    The type Validator is a struct with an embedded interface API. This means, a Validator instance has an embedded member that implements the API interface, and since it is embedded, Validator also implemented the API interface. However, note that you have to initialize Validator.API to an implementation first. Something like this should work:

    v:=Validator{API:&APIService{}}
    

    With this, v.Get() will call the embedded APIService.Get.