In one package I have an interface Repository
that has a method GetReporter
that returns an interface Reporter
. This is used by a function Execute
that takes a Repository
and gets its Reporter
via the GetReporter
function.
In another package I have a struct GithubRepository
that has a method GetReporter
that returns a GithubReporter
.
In a third package I want to call the Execute
function out of package #1 with a GithubRepository
instance.
I am trying to have package 1 and 2 independent of each other, without one importing something from the other. The 3rd package should combine the first two.
Golang returns:
cannot use githubRepository (type GithubRepository) as type Repository in argument to Execute:
GithubRepository does not implement Repository (wrong type for GetReporter method)
have GetReporter(string) GithubReporter
want GetReporter(string) Reporter
Code:
package main
// Package #1
type Repository interface {
GetReporter(string) Reporter
}
type Reporter interface {
ChangeStatus(string) error
}
func Execute(r Repository) {
// Do something with the repository
}
// Package #2
type GithubRepository struct {
}
type GithubReporter struct {
}
func (repo *GithubRepository) GetReporter(sha string) GithubReporter {
return GithubReporter{}
}
func (reporter *GithubReporter) ChangeStatus(status string) error {
// Change the status
return nil
}
// Package #3
func main() {
githubRepository := GithubRepository{}
Execute(githubRepository)
}
Go Playground: https://play.golang.org/p/ph0sZnyAC5I
It was impossible to make two package independent in such a case. However, with go1.9 and its type alias, this can be done.
First, as go proverbs say, A little copy is better than a little dependency. You should copy the part of definition of Reporter
to package B, and change the signature according to it: func (repo GithubRepository) GetReporter(sha string) Reporter
.
Yet the compiler won't understand that the two interface is the samething. But with the help of type alias, it can be worked around. Change both definition type Reporter interface {...}
to type Reporter = interface {...}
. And it will compile now.
Use GithubRepository
and GithubReporter
as value receiver as you have not create variable as pointer. And return interface in method GetReporter
func (repo GithubRepository) GetReporter(sha string) Reporter {
return GithubReporter{}
}
func (reporter GithubReporter) ChangeStatus(status string) error {
// Change the status
return nil
}
Hope this will help.
See in action: https://play.golang.org/p/Gugm3LetqHU
If you have interface in different package, these is no need to do special things, just point to that interface with package.
In package A
package A
type Repository interface {
GetReporter(string) Reporter
}
type Reporter interface {
ChangeStatus(string) error
}
func Execute(r Repository) {
r.GetReporter("report:r").ChangeStatus("status:s")
}
In package B
package B
import (
"fmt"
"test/A"
)
type GithubRepository struct {
}
type GithubReporter struct {
}
func (repo GithubRepository) GetReporter(sha string) A.Reporter {
fmt.Println(sha)
return GithubReporter{}
}
func (reporter GithubReporter) ChangeStatus(status string) error {
// Change the status
fmt.Printf(status)
return nil
}
May be you can try Import Dot