【问题标题】:Check if Go type shadows/implements one function of an embedded type's interface检查 Go 类型是否隐藏/实现嵌入式类型接口的一项功能
【发布时间】:2021-04-07 18:44:04
【问题描述】:
type A interface {
  MyFunc()
}

type A struct {
}

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

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

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

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

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

【问题讨论】:

  • 方法集确定是否实现了接口,B 方法集在这两种情况下都包含MyFunc()。定义不同的MyFunc() 不会更改方法集。
  • 我不明白这与我的问题有什么关系。我知道方法集决定了接口。我想检查它是否因为嵌入 A 或被 B 充满(比如没有嵌入 A 时)而被填满。用例:A 实现了一个标准行为,现在我想检查 B 是否用它自己的实现覆盖了这个标准行为。
  • 这是相关的,因为您的示例试图在编译时使用类型系统断言条件,而类型系统没有办法做到这一点。

标签: go interface embedding shadowing


【解决方案1】:

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


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

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


至于技术细节:

类型的方法集是编译器确定类型是否满足接口所需的全部内容。这些方法是如何到达那里的无关紧要。

不幸的是,Go 规范对这一点并不是非常直截了当,但可以拼凑出一个解释。

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

合法的选择器:

选择器f 可以表示类型T 的字段或方法f,或者它可以引用T 的嵌套嵌入字段的字段或方法f

那么b.Myfunc 是合法的选择器吗?是的,因为它引用了嵌入结构的方法。这种方法称为promoted。那么:

给定一个结构类型S和一个定义类型T,提升的方法包含在结构的方法集中[...继续描述嵌入T*T的规则]

最后:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-26
    • 1970-01-01
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-16
    相关资源
    最近更新 更多