首页 > 解决方案 > 带有接收器的函数,它遍历 go 中结构的某些字段

问题描述

我是一个 Golang 新手,试图构建一个简单的 CLI。我正在将 API 调用有效负载转换为一个结构,并希望将此结构中的一些信息格式化为一个很好的可打印字符串。我要打印的信息之一来自结构数组,如本例所示:

type Pokemon struct {
    Abilities []struct {
        Ability struct {
            Name string `json:"name"`
            URL  string `json:"url"`
        } `json:"ability"`
        IsHidden bool `json:"is_hidden"`
        Slot     int  `json:"slot"`
    } `json:"abilities"`
    Height int    `json:"height"`
    ID     int    `json:"id"`
    Name   string `json:"name"`
    Types  []struct {
        Slot int `json:"slot"`
        Type struct {
            Name string `json:"name"`
            URL  string `json:"url"`
        } `json:"type"`
    } `json:"types"`
    Weight int `json:"weight"`
}
}

我正在尝试编写一个通用的受体函数,它遍历一些结构数组的字段并将其字段连接到一个字符串中。我可以做一个专门迭代某些字段的函数,如下所示:

func (p Pokemon) stringifyPokemonAbilities() string {
    var listOfAbilities []string
    for _, ability := range p.Abilities {
        listOfAbilities = append(listOfAbilities, ability.Ability.Name)
    }
    return strings.Join(listOfAbilities[:], " / ")
}

返回例如synchronize / inner-focus

像这样工作,我将不得不向该Type领域编写几乎相同的功能。我的问题是,如何使这个函数更通用,接受一个字段并对其进行迭代。有什么想法吗?

标签: gostructinterface

解决方案


你可以使用relfect来做到这一点。有一个写得很好的教程,你可以看看。

根据你给的结构,我写了一个demo。主要思想是通过名称找到结构体,然后迭代切片,在结构体中找到名称。

p.stringifyPokemon("Types")您可以使用or p.stringifyPokemon("Abilities")now得到答案。

func (p Pokemon) stringifyPokemon(field string) string {
    value := reflect.ValueOf(p)
    struct1 := value.FieldByName(field)

    if !struct1.IsValid() {
        return ""
    }

    if struct1.Type().Kind() != reflect.Slice {
        return ""
    }

    ans := make([]string, 0)

    for i := 0; i < struct1.Len(); i++ {
        slice1 := struct1.Index(i)
        if slice1.Type().Kind() != reflect.Struct {
            continue
        }

        for j := 0; j < slice1.NumField(); j++ {
            struct2 := slice1.Field(j)
            if struct2.Type().Kind() != reflect.Struct {
                continue

            }
            name := struct2.FieldByName("Name")
            if name.Kind() != reflect.String {
                continue
            }
            ans = append(ans, name.String())
        }
    }

    return strings.Join(ans[:], " / ")
}


推荐阅读