typeAstruct{namestringnamestring// Compile error: name redeclared [DuplicateDecl]}func(this*A)name(){}// Compile error: Field and method with the same name name [DuplicateFieldAndMethod]
但上述代码中 Go 并不会真的将 A 的属性 Name 抽取出来放入类型 B 中,这种“提升”其实只是一种便捷的访问方式,在对属性的查找过程中实现:如果当前类型的属性没有匹配项,则对下一级的内嵌类型进行查找,并依此逻辑递归直到查找完所有内嵌类型。这时便会面临一个问题:如果同一层级的内嵌类型有相同属性,那么编译器就不知道到底应该使用哪一个。例如代码:
此时编译器会提示错误,从而引导用户提供更明确的选择,例如:b.A.Name
方法的等价性校验
方法missingMethod(V Type, T Interface, static bool) (method, wrongType Func)用来判断类型V是否实现了接口T,如果返回值为 nil, 则 V 实现了接口 T; 否则返回值表示查找到的第一个 V 没有实现 T 的方法。
这里涉及到的逻辑分为两个部分:一是对于 T 中的每个方法,按照方法名在 V 中进行查找;二是如果在 V 中找到了同名方法的话,判断两个方法是否是同一个类型,即判断是否拥有一致的参数列表与返回值列表。第一部分的思路与属性的查找一致;第二部分为了支持泛型,在此处并没有使用类型的等价规则中的等价比较算法,这里叫着类型统一(Type unification),当前的实现逻辑在文件$GCROOT/compile/internal/types2/unify.go中,入口方法是func (u *unifier) unify(x, y Type) bool {}为什么叫类型统一呢?如果将类型想象成一个树形结构(或者图)的话,那么类型的等价规则的核心思想就是比较两个类型的结构是否一致,并且各对应结点的类型是否等价。这在没有类型参数的情况下是合理的,但是类型参数的引入使得该逻辑变得不够完善。在对泛型数据结构的讨论中我们提到过类型模版的概念,意在说明包含泛型申明的类型可以表示不同的实际类型,例如,假如 T1 与 T2 都是类型参数,那么一个实际类型map[int]bool可以用如下类型来表示:
type A struct {
Name string
}
type B struct {
Name string
}
type C struct {
A
B
}
func main() {
var b B
name := b.Name // Compile error: ambigous selector b.Name [AmbigousSelector]
}