带有接收器的函数在 go 中迭代结构的某个字段

function with receiver that iterates through some field of struct in 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 字段编写几乎相同的函数。我的问题是,如何使这个函数更通用,接受一个字段并对其进行迭代。有什么想法吗?

您可以使用 relfect. There is a well written tutorial 来做到这一点,您可以看看。

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

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

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[:], " / ")
}