MST

星途 面试题库

面试题:Go 值调用方法集特点之高级题

假设有如下代码: ```go package main import "fmt" type Animal struct { Name string } func (a Animal) Speak() { fmt.Printf("%s makes a sound\n", a.Name) } func (a *Animal) Move() { fmt.Printf("%s is moving\n", a.Name) } func main() { dog := Animal{Name: "Dog"} var dogPtr *Animal = &dog var animals []interface{} animals = append(animals, dog) animals = append(animals, dogPtr) for _, v := range animals { switch v := v.(type) { case Animal: v.Speak() case *Animal: v.Move() } } } ``` 这段代码能否正确运行并输出预期结果?如果不能,请指出原因并说明Go值调用方法集特点在此处的体现。
47.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 代码能否正确运行及原因
    • 这段代码不能正确运行。
    • 原因在于Go语言的类型断言机制。在for _, v := range animals循环中,v在每次迭代时的类型是interface{},当进行类型断言switch v := v.(type)时,vcase Animal:分支中是一个新的Animal值(它是从interface{}中提取出来的),而不是原来的dog变量或其指针dogPtr。所以当执行v.Speak()时,调用的是这个新的Animal值的Speak方法,这没问题。但是在case *Animal:分支中,v是从interface{}中提取出来的指针,而animals切片中实际存储的dogAnimal类型)在进行类型断言转换为指针时会失败,因为Animal类型的值本身不是指针类型,无法直接转换为*Animal指针类型,所以会导致运行时错误。
  2. Go值调用方法集特点在此处的体现
    • 值接收器方法集:对于定义了值接收器的方法(如func (a Animal) Speak()),可以通过值类型或指针类型调用。因为Go语言在调用值接收器方法时,如果接收者是指针,会自动解引用指针来调用方法。例如,dogPtr.Speak()也能正确调用Speak方法。
    • 指针接收器方法集:对于定义了指针接收器的方法(如func (a *Animal) Move()),只能通过指针类型调用。如果通过值类型调用,编译器会报错。在这个例子中,dog.Move()会报错,因为dogAnimal值类型,而Move方法需要*Animal指针类型接收器。在类型断言中,由于animals切片中包含Animal值类型的dog,在case *Animal:分支中进行类型断言转换时,Go语言不会自动将Animal值类型转换为*Animal指针类型,所以导致运行时错误,这体现了指针接收器方法集调用对类型的严格要求。