嵌套接口:X未实现Y(Z方法的类型错误)

嵌套接口:X未实现Y(Z方法的类型错误)

问题描述:

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

在一个包中,我有一个接口 Repository code>,该接口的方法是 GetReporter 返回接口 Reporter code>。 函数 Execute code>使用该函数,该函数采用 Repository code>,并通过 GetReporter code>函数获取其 Reporter code>。 p>

在另一个包中,我有一个结构体 GithubRepository code>,该结构具有返回 GithubReporter code>的方法 GetReporter code>。 p>

在第三个包中,我想使用 GithubRepository code>实例从包#1中调用 Execute code>函数。 p>

我正在尝试使软件包1和2彼此独立,而又没有一个从另一个导入。 第三个程序包应结合前两个。 执行: GithubRepository未实现存储库(GetReporter方法的类型错误) 具有GetReporter(字符串)GithubReporter 想要GetReporter(字符串)Reporter code> pre>

Code : p>

 包main 
 
 //包#1 
 
type存储库接口{
 GetReporter(string)Reporter 
} 
 
type Reporter接口{  
 ChangeStatus(string)错误
} 
 
func Execute(r存储库){
 //对存储库执行某些操作
} 
 
 //软件包#2 
 
type GithubRepository结构{
  } 
 
type GithubReporter结构{
} 
 
func(仓库* GithubRepository)GetReporter(sha字符串)GithubReporter {
返回GithubReporter {} 
} 
 
func(报告* GithubReporter)ChangeStatus(状态字符串) 错误{
 //更改状态
返回nil 
} 
 
 //包#3 
 
func main(){
 githubRepository  := GithubRepository {} 
 Execute(githubRepository)
} 
  code>  pre> 
 
 

去游乐场: https://play.golang.org/p/ph0sZnyAC5I p> div>

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