假设有两个不同类型的struct,都实现了某个接口,怎么只用一个方法去遍历它们组成的数组,并且调用它们实现的接口。

package main

import (
	"fmt"
	"reflect"
)

// 某接口
type ICommon interface {
	GetName() string
}

// 第一个结构体,实现了ICommon接口
type Animal struct {
	name string
	age  int64
}

func (u *Animal) GetName() string {
	return u.name
}

func (u *Animal) GetAge() int64 {
	return u.age
}

// 第二个结构体,实现了ICommon接口
type Human struct {
	name string
}

func (p *Human) GetName() string {
	return p.name
}

// 1、先判断一个interface变量是不是数组或切片
// 2、再使用反射和断言确定数组内的元素是不是实现了某个接口
// 3、调用数组成员的接口方法
func GetNamesFromList(list interface{}) []string {
	names := make([]string, 0)

	switch reflect.TypeOf(list).Kind() {
	case reflect.Slice, reflect.Array:
		s := reflect.ValueOf(list)
		for i := 0; i < s.Len(); i++ {
			o, ok := s.Index(i).Interface().(ICommon)
			if ok {
				names = append(names, o.GetName())
			}
		}
	}

	return names
}

func main() {
    // 构造两个不同类型的数组
	animals := make([]*Animal, 0)
	animals = append(animals, &Animal{name: "dog"})
	animals = append(animals, &Animal{name: "cat"})
	animals = append(animals, &Animal{name: "bird"})

	humans := make([]*Human, 0)
	humans = append(humans, &Human{name: "XiaoMin"})
	humans = append(humans, &Human{name: "XiaoHong"})
	humans = append(humans, &Human{name: "XiaoQiang"})

    // 使用同一个函数遍历上述两个不同类型的数组
	fmt.Println(GetNamesFromList(animals))
	fmt.Println(GetNamesFromList(humans))
}