I am practicing writing idiomatic Go code and discovered that interfaces should be declared in packages which are consuming them since they're implicit. However I came to this situation where by in the second package (package b) I want a function to call the receiver function of a struct in package a without coupling it tightly.
So naturally, I declare an interface in package b with the signature of the function I want to call from package a. The problem is that this function accepts an argument of a certain type which is an interface declared in package a. As I don't want package b to import package a, I defined an interface in package b with the exact same signature as the one which exists in package a. The playground link below shows the example code.
package main
import (
"fmt"
"log"
)
func main() {
manager := &Manager{}
coach := NewRunnerCoach(manager)
fmt.Println("Done")
}
// package a
type Runner interface {
Run()
}
type Manager struct {
}
func (o *Manager) RegisterRunner(runner Runner) {
log.Print("RegisterRunner")
}
func (o *Manager) Start() {
log.Print("Start")
}
// package b
type RunnerCoach struct {
runner *FastRunner
}
func NewRunnerCoach(registerer runnerRegisterer) *RunnerCoach {
runnerCoach := &RunnerCoach{&FastRunner{}}
registerer.RegisterRunner(runnerCoach.runner)
return runnerCoach
}
type FastRunner struct {
}
func (r *FastRunner) Run() {
log.Print("FastRunner Run")
}
// define ther registerer interface coach is accepting
type runnerRegisterer interface {
RegisterRunner(runner RunnerB)
}
// declaring a new interface with the same signature because we dont want to import package a
// and import Runner interface
type RunnerB interface {
Run()
}
This code does not compile. So the question here is that, am I using interface wrongly or should concrete types be defined in a separate package or lastly, is there a better code pattern for the problem I'm trying to solve?
EDIT: To clarify, package a and b does not import each other. The main() code exists in a separate package which connects these two.