如何使用相同的方法签名实现两个不同的接口

tar*_*lah 7 interface go

假设我必须实现在两个不同的包中声明的两个不同的接口(在两个不同的分离项目中).

我有包裹 A

package A

type interface Doer {
    Do() string
}

func FuncA(Doer doer) {
     // Do some logic here using doer.Do() result

     // The Doer interface that doer should implement, 
     // is the A.Doer
}
Run Code Online (Sandbox Code Playgroud)

并在包中 B

package B

type interface Doer {
    Do() string
}

function FuncB(Doer doer) {
    // some logic using doer.Do() result

     // The Doer interface that doer should implement, 
     // is the B.Doer
}
Run Code Online (Sandbox Code Playgroud)

在我的main包裹中

package main

import (
    "path/to/A"
    "path/to/B"
)

type C int

// this method implement both A.Doer and B.Doer but
// the implementation of Do here is the one required by A !
func (c C) Do() string {
    return "C now Imppement both A and B"
}

func main() {
    c := C(0)
    A.FuncA(c)
    B.FuncB(c) // the logic implemented by C.Do method will causes a bug here !
}
Run Code Online (Sandbox Code Playgroud)

如何应对这种情况?

Von*_*onC 7

正如常见问题提到的那样

使用其他语言的经验告诉我们,使用具有相同名称但签名不同的各种方法偶尔会有用,但在实践中它也可能令人困惑和脆弱.
仅根据名称进行匹配并要求在类型中保持一致性是Go类型系统中的主要简化决策.

在您的情况下,您将满足两个接口.

您可以通过执行以下操作来测试对象(接口类型)是否满足另一种接口类型A.Doer:

if _, ok := obj.(A.Doer); ok {
}
Run Code Online (Sandbox Code Playgroud)

OP增加:

但是Do要满足的方法中实现的逻辑与中的A完全不同B.

然后你需要在你的对象周围实现一个包装器:

  • a DoerA,将您的对象C作为字段,并A.Do()以满足A.Do()应该如何工作的方式实现
  • a DoerB,具有与C字段相同的对象,并B.Do()以满足B.Do()应该如何工作的方式实现

这样,您将知道哪个Doer传递给期望a A.Doer或a 的函数B.Doer.
你不会实现Do()你的原始对象上的方法C,这将是无法应付的不同的逻辑A.Do()B.Do().