Golang 推导接口

3

这里只是一个与语言设计相关的简单问题。 在像Swift这样的语言中,为了使结构体/类符合协议/接口,需要明确地声明它。

struct Dog: Animal {
    // implementation of Animal protocols here
}

但是为什么在Go语言中,没有明确的方式来显示一个结构体符合哪些接口呢?

这难道不会使事情变得不清晰吗?还是说背后还有其他原因?


由于Go语言的推断接口,接口可以以临时的方式添加到现有代码中。请参见https://dev59.com/RWXWa4cB1Zd3GeqPIweV#62297796。 - user12817546
2个回答

7
这允许进化以提供接口,即使是传统类型(从未明确声明遵守该接口)。如果这些类型已经提供了正确的方法(即与您指定的接口相同的API),则它们将满足该接口。这样可以在那些遗留类型(不知道您的接口存在)和接受该接口实例的程序之间保持低耦合度。请参见“Go接口的一些示例是什么?”。“Go的接口不是Java或C#接口的变体,它们更多。它们是大规模编程和适应性、进化设计的关键。”“重要的是我不必花时间事先设计某种类型层次结构,然后再重新排列两三次才能完成。重要的甚至不是做对很容易——事实上,我根本不用担心它,可以继续进行实际算法。”

这些引用来自于2012年的一篇文章,以及这个线程,您可以在其中阅读Rob Pike的评论

“在面向对象的语言中,我一直感到不舒服的是我们可以将Circle、Square等子类定义为Shape(比方说),但那是我们能做出的唯一设计决策。
如果我们想要将这些东西沿其他轴线对齐(说白了),比如拓扑层级或植物属分类,如果你是一个园艺工作者,你可能会迷失方向或陷入多重继承的泥潭。”


3

扩展VonC的答案。

从问题中可以看出:

但为什么在Go中,没有明确的方式显示一个结构体符合哪些接口呢?

实际上有一些方法。请参见 Go FAQ: 如何确保我的类型满足一个接口?

假设我们有以下接口:

type Sayer interface {
    Say() string
}

我们想要创建一个实现它的新类型:

type MySayer struct{}

func (ms MySayer) Say() string {
    return "Foo"
}

在这种情况下,MySayer 实现了 Sayer。为确保它实现了该接口,您可以添加以下行:
var _ Sayer = MySayer{}

如果您打错了什么,比如将您的Say()方法命名为Sai(),那么它将成为编译时错误。
然而,这只是一个编译时的“检查”,它并没有记录MySayer实现了Sayer。为此,您可以添加一个“虚拟”的方法,其名称本身就可以记录这个属性:
type Sayer interface {
    Say() string
    ImplementsSayer()
}

现在,任何类型要实现 Sayer,它们必须声明一个名为 ImplementsSayer() 的方法,这个方法一眼就能告诉你它实现了 Sayer
func (MySayer) ImplementsSayer() {}

您甚至不需要给接收器命名,因为它并未被使用。这行代码用简单的英语描述了:"MySayer实现了Sayer"
由于该方法是导出的(以大写字母开头),因此它也出现在文档中,直截了当地告诉您它实现了Sayer。但正如常见问题解答所说:

大多数代码都不使用这种约束条件,因为它们限制了接口思想的实用性。然而,有时候它们是必要的,以解决类似接口之间的歧义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接