方法调用
- 直接调用:当结构体包含匿名字段时,该匿名字段的方法就像直接定义在结构体上一样可以被调用。例如:
package main
import "fmt"
type Animal struct {
}
func (a Animal) Speak() {
fmt.Println("I'm an animal")
}
type Dog struct {
Animal
}
func main() {
d := Dog{}
d.Speak() // 可以直接调用匿名字段Animal的Speak方法
}
- 方法重写:如果结构体中定义了与匿名字段同名的方法,那么结构体自身的方法会覆盖匿名字段的方法。例如:
package main
import "fmt"
type Animal struct {
}
func (a Animal) Speak() {
fmt.Println("I'm an animal")
}
type Dog struct {
Animal
}
func (d Dog) Speak() {
fmt.Println("I'm a dog")
}
func main() {
d := Dog{}
d.Speak() // 调用的是Dog结构体自身的Speak方法,而非Animal的
}
类型断言
- 基于接口的类型断言:如果一个接口值实际指向的是包含匿名字段的结构体,类型断言时会根据结构体及其匿名字段实现的接口来判断。例如:
package main
import "fmt"
type Animal interface {
Speak()
}
type Cat struct {
}
func (c Cat) Speak() {
fmt.Println("I'm a cat")
}
type BigCat struct {
Cat
}
func main() {
var a Animal = BigCat{}
if cat, ok := a.(Cat); ok {
cat.Speak() // 可以通过类型断言获取到匿名字段类型并调用方法
}
}
- 判断类型兼容性:在类型断言时,Go会将包含匿名字段的结构体视为其匿名字段类型的一种扩展。只要结构体满足接口的方法集,就可以断言为接口类型。
接口实现
- 隐式实现:如果结构体包含一个匿名字段,且该匿名字段实现了某个接口,那么这个结构体也隐式地实现了该接口。例如:
package main
import "fmt"
type Runner interface {
Run()
}
type Horse struct {
}
func (h Horse) Run() {
fmt.Println("Horse is running")
}
type RaceHorse struct {
Horse
}
func main() {
var r Runner = RaceHorse{}
r.Run() // RaceHorse因为包含Horse匿名字段,隐式实现了Runner接口
}
- 方法集完备性:类型检查机制会检查结构体及其匿名字段的方法集,确保满足接口的所有方法,从而判断结构体是否实现了该接口。如果结构体自身定义了与接口方法同名的方法,会优先使用结构体自身的方法来满足接口。