【问题标题】:Struct does not implement interface if it has a method whose parameter implements interfaceStruct如果有参数实现接口的方法,则不实现接口
【发布时间】:2018-08-21 08:52:37
【问题描述】:

我有一个包,里面有两个接口

package main

type A interface {
    Close()
}

type B interface {
    Connect() (A, error)
}

我还有两个实现这些接口的结构

type C struct {
}

func (c *C) Close() {

}

type D struct {
}

func (d *D) Connect() (*C, error) {
    c := new(C)
    return c, nil
}

接下来我有一个函数,它作为参数需要一个实现接口 B 的对象

func test(b B) {
}

最后,在 main() 函数中,我创建了 D 结构对象并想调用 test() 函数

func main() {
    d := new(D)
    test(d)
}

如果我尝试构建该软件包,我会遇到错误。

在测试的参数中不能使用 d(类型 *D)作为类型 B: *D 没有实现 B(Connect 方法的类型错误) 有 Connect() (*C, 错误) 想要 Connect() (A, error)

这是我的代码的简单示例,我使用外部包并希望模拟结构进行测试。使用接口而不是类型有什么解决方案吗?

【问题讨论】:

  • Connect() 改为返回(A, error)

标签: go struct interface


【解决方案1】:

为了实现接口,需要关注的是:

Go 类型通过实现接口的方法来满足接口 界面,仅此而已。该属性允许定义接口 并且无需修改现有代码即可使用。它使一种 促进关注点分离和改进的结构类型 代码重用,并且更容易建立在出现的模式上 代码开发。

您得到的错误是因为您用作测试函数参数的结构D 没有实现接口。这背后的原因是您与接收器D 一起使用的函数Connect 不同。因为它有不同的返回类型:

func (d *D) Connect() (*C, error) { // the struct D does not implement the interface B because of wrong function definition to interface B function
    c := new(C)
    return c, nil
}

如果你想实现接口B,函数定义及其返回类型应该匹配接口B中的函数,即

type B interface {
    Connect() (A, error)
}

所以如果你想实现接口,你使用的 Connect 方法应该匹配接口 B 的 Connect 方法

package main

type A interface {
    Close()
}
type B interface {
    Connect() (A, error)
}

type C struct {
}

func (c *C) Close() {

}

type D struct {
}

func (d *D) Connect() (A, error) {
    c := new(C)
    return c, nil
}

func test(b B) {}

func main() {
    d := new(D)
    test(d)
}

查看Go Playground

考虑用这个简单的接口来表示一个可以将自己与另一个值进行比较的对象:

type Equaler interface {
    Equal(Equaler) bool
}

还有这种类型,T:

type T int
func (t T) Equal(u T) bool { return t == u } // does not satisfy Equaler

T.Equal 的参数类型是 T,而不是字面上要求的 Equaler 类型。

在 Go 中,类型系统不提倡 Equal 的参数;这是程序员的责任,正如 T2 类型所说明的那样,它确实实现了 Equaler:

type T2 int
func (t T2) Equal(u Equaler) bool { return t == u.(T2) }  // satisfies Equaler

【讨论】:

  • 好吧,我想如果 *C 实现了 A 接口就可以使用它。想象一下 C 和 D 来自外部包,我无法更改它们的功能。如何嘲笑他们?
  • @Abdulafaja 您可以做的一件事是从另一个包中导入结构。如果您无法更改功能,则创建一个应该实现 B 的新功能。
  • 谢谢,这是最有帮助的。我创建了另一个覆盖外部结构的结构,并添加了正确的功能(如这里stackoverflow.com/questions/28800672/…)。但我仍然认为编译器应该通过我的代码
【解决方案2】:

Connect 方法的返回类型应该是 A 而不是 *C

您定义Connect 方法的方式是它应该返回一个接口,而不是特定类型。您仍然可以返回 *C,因为它实现了 A 接口。

package main

type A interface {
    Close()
}

type B interface {
    Connect() (A, error)
}

type C struct {
}

func (c *C) Close() {
}

type D struct {
}

func (d *D) Connect() (A, error) {
    c := new(C)
    println("successfully created new C:", c)
    return c, nil
}

func test(b B) {
    b.Connect()
}

func main() {
    d := new(D)
    test(d)
}

输出

成功创建新C:0xe28f0

自己试试here

【讨论】:

  • 谢谢,但是如果我的包中没有 struct C 和 D 并且我想模拟它们怎么办?我无法编辑这些函数
  • @Abdulafaja 你不想模拟函数。那就是你可能被告知做的事情是正确的。不是。
猜你喜欢
  • 2016-08-17
  • 1970-01-01
  • 2019-01-14
  • 1970-01-01
  • 1970-01-01
  • 2019-01-08
  • 1970-01-01
  • 2013-04-14
  • 1970-01-01
相关资源
最近更新 更多