检查 Go 类型是否隐藏/实现了嵌入类型接口的一项功能

问题描述

type A interface {
  MyFunc()
}

type A struct {
}

func (a *A) MyFunc() {...}
 
type B struct {
  *A
}
var _ A = &B{}
var _ A = (*B)(nil)

B 实现了接口 A 因为嵌入了 A。到目前为止,一切都很好。

但是我如何(静态地或在运行时)检查 B 是否实现了自己的 MyFunc 版本?

更新:无法在编译时静态检查。

func (b *B) MyFunc() {...}
var _ ??? = &B{}
var _ ??? = (*B)(nil)

解决方法

tl;dr 你不能,因为@JimB 提到的原因。


要回复您的最新评论: “我只是想确保框架的用户得到一些关于如何最好地使用界面的提示。”

如果我的目标是向我的用户推荐最佳实践,我会在某处记录下来。是的,有一个没有人阅读文档的神话,但无论如何,如果您允许 BA 组合,您的设计语义正是“B 可以具有 A 的行为”。所以警告你的用户这一点是没有实际意义的。这就像你给了你的客户一把锤子并说“记住,这是一个 B 型锤子”。好吧,它仍然是一把锤子。如果您想为您的客户提供强大的功能,那么他们从哪里得到锤子以及任何相关的警告都是无关紧要的。


至于技术细节:

一个类型的方法集就是编译器判断该类型是否满足某个接口所需要的。方法如何到达那里是无关紧要的。

不幸的是,Go 规范在这一点上并不是非常简单,但可以拼凑出一个解释。

如果 f 是表示该字段或方法 x 的合法选择器,则结构 x.f 中嵌入字段的字段或方法 f 被称为提升。

合法选择器:

选择器 f 可以表示类型 T 的字段或方法 f,也可以指代 {{1} 的嵌套嵌入字段的字段或方法 f }

那么 T 是合法的选择器吗?是的,因为它指的是嵌入结构的方法。这种方法被称为promoted。然后:

给定结构类型 b.Myfunc 和定义的类型 S,提升的方法包含在结构的方法集中 [...继续描述嵌入 T 与 { 的规则{1}}]

最后:

一个类型的方法集决定了该类型实现的接口

这就是您可以从规格中获得的全部信息。没有提及为什么或如何将方法包含在方法集中以满足接口的目的。

现在唯一的附加信息是,当 T 在其方法中确实设置了 *T 时,直接和通过嵌入 B,如果您调用 MyFunc,{ {1}} 的实现由于 depth 规则而运行,这是一种正式的方式,实质上定义了类似于 OOP 中覆盖的行为:选择器 A 表示 {{ 1}} 在最浅的深度,当 b.MyFunc 由嵌入类型 B 产生时,它的深度是它在 x.f+1 中的深度,而直接声明的方法的深度为 0.