面试题答案
一键面试Zoo结构体实现Animal接口
由于Dog
和Cat
结构体已经分别实现了Animal
接口的Speak
方法,Zoo
结构体通过组合Dog
和Cat
结构体,在Go语言中,Zoo
结构体可以间接实现Animal
接口。只要通过Zoo
结构体实例去调用Speak
方法时,Go语言会在组合的结构体的方法集中查找该方法。例如:
package main
import "fmt"
// Animal接口
type Animal interface {
Speak()
}
// Dog结构体
type Dog struct{}
// Dog实现Speak方法
func (d Dog) Speak() {
fmt.Println("Dog barks")
}
// Cat结构体
type Cat struct{}
// Cat实现Speak方法
func (c Cat) Speak() {
fmt.Println("Cat meows")
}
// Zoo结构体,组合Dog和Cat
type Zoo struct {
Dog
Cat
}
在上述代码中,Zoo
结构体组合了Dog
和Cat
,虽然Zoo
结构体本身没有显式实现Speak
方法,但是由于它组合的Dog
和Cat
都实现了Speak
方法,Zoo
的实例可以调用Speak
方法。
组合方法集的形成机制对接口实现的影响
- 方法集查找规则:在Go语言中,结构体类型的方法集是指该类型定义的所有方法的集合。对于组合结构体(如
Zoo
),其方法集包含其直接定义的方法以及其嵌入的结构体的方法。当通过Zoo
实例调用Speak
方法时,Go语言会先在Zoo
本身的方法集中查找,如果没找到,则会在其嵌入的结构体(Dog
和Cat
)的方法集中查找。 - 接口实现规则:Go语言中,只要一个类型的方法集满足接口的方法列表,该类型就被认为实现了这个接口。对于
Zoo
结构体,由于其嵌入的Dog
和Cat
都实现了Animal
接口的Speak
方法,当Zoo
实例调用Speak
方法时,总能找到对应的实现,所以Zoo
结构体也被认为实现了Animal
接口。 - 潜在的冲突问题:如果
Dog
和Cat
的Speak
方法实现不同,且Zoo
通过实例调用Speak
方法时,编译器会报错,因为这会导致调用的歧义。解决方法可以是在Zoo
结构体中显式实现Speak
方法,或者通过指定具体的嵌入结构体来调用(如z.Dog.Speak()
或z.Cat.Speak()
)。