I want to compose a type of another type, but replace one of the fields (which is an interface value) with a fake. The problem I am getting is the underlying field is being used, so I can't seem to override the field.
I've demoed the problem here: https://play.golang.org/p/lHGnyjzIS-Y
package main
import (
"fmt"
)
type Printer interface {
Print()
}
type PrinterService struct {}
func (ps PrinterService) Print() { fmt.Println("PrinterService") }
type Service struct {
Client PrinterService
}
func (s Service) PrintViaMethod() { s.Client.Print() }
type FakeService struct {
Service
Client Printer
}
type SomeOtherService struct {}
func (sos SomeOtherService) Print() { fmt.Println("SomeOtherService") }
func main() {
s := FakeService{Client: SomeOtherService{}}
s.PrintViaMethod()
}
Why does it print "PrinterService"
? I want it to print "SomeOtherService"
.
Thanks.
Because that's what your code says to do.
PrintViaMethod
callss.Client.Print()
, ands.Client
is a (zero value) instance ofPrinterService
, which outputsPrinterService
.What you probably want is to call
s.Print()
inmain()
. I don't see any reason for yourPrintByMethod
function at all.As per
Flimzy
you are calling prints.Client.Print()
which is of typePrinterService
implemented as receiver toPrint()
function printingPrinterService
. You can also change type ofClient
PrinterService
inService
struct toSomeother service
By
s.PrintViaMethod()
, you are calling the promoted methodFakeService.Service.PrintViaMethod()
, and the method receiver will beFakeService.Service
which is of typeService
, andService.PrintViaMethod()
callsService.Client.Print()
, whereService.Client
is of type whichPrinterService
, that's why it prints"PrinterService"
.In Go there is embedding, but there is no polymorphism. When you embed a type in a struct, methods of the embedded type get promoted and will be part of the method set of the embedder type. But when such a promoted method is called, it will get the embedded value as the receiver, not the embedder.
To achieve what you want, you would have to "override" the
PrintViaMethod()
method by providing your implementation of it for theFakeService
type (withFakeService
receiver type), and inside it callFakeService.Client.Print()
.By doing so
s.PrintViaMethod()
will denote theFakeService.PrintViaMethod()
method as that will be at the shallowest depth where thePrintViaMethod()
exists (and notFakeService.Service.PrintViaMethod()
). This is detailed in Spec: Selectors.For example:
Then the output will be (try it on the Go Playground):
See related questions and answers with more details:
Go embedded struct call child method instead parent method
Does fragile base class issue exist in Go?