将配置结构加载到 go 中后,访问嵌套属性时出现问题

After loading a config struct into go, problems with accessing nested properties

所以我想在我的程序中加载一个 config.yaml 文件到我的程序中。

defaultTimeout: 0.25
defaultWorkspace: ibm
workspaces:
  ibm:
    client: 47943938
    defaultGoal: 27.5
    projects:
      - 159929907
      - 160046030
      - 160064503
  pp:
    defaultGoal: 5.5
    project: 160064503

因此我创建了以下结构:

type Config struct {
    DefaultTimeout   float64 `yaml:"defaultTimeout"`
    DefaultWorkspace string  `yaml:"defaultWorkspace"`
    Workspaces       struct {
        IBM struct {
            Client      int     `yaml:client`
            DefaultGoal float64 `yaml:"defaultGoal"`
            Projects    []int   `yaml:"projects"`
        }
        PP  struct {
            DefaultGoal float64 `yaml:"defaultGoal"`
            Project     int     `yaml:project`
        }
    }
}

基本上,我列出了具有不同属性的不同工作区和一个 属性 共同点:DefaultGoal。现在我想以干净高效的方式访问此 属性。

现在我有了决定我要选择哪个工作区的参数 *workspaceName。所以问题是我如何将其用作 Workspace 我想选择的键,然后进一步获取相应条目的 DefaultGoal?

我尝试了以下(config 是从 yaml 源加载的结构)

wsConf := reflect.Indirect(reflect.ValueOf(config.Workspaces)).FieldByName(*workspaceName)

但是我有 reflect.Value,我必须将其转换回结构以评估 DefaultGoal

这里有什么好的处理方法吗?感谢您的帮助!

与其玩反射(reflect 包),不如使用 map[string]interface{} 作为字段类型(特别是 Workspaces 字段),然后从中处理项目映射为特定工作区。

type Config struct {
    DefaultTimeout   float64 `yaml:"defaultTimeout"`
    DefaultWorkspace string  `yaml:"defaultWorkspace"`
    Workspaces       map[string]interface{} `yaml: workspaces`
}

type IBM struct {
            Client      int     `yaml:client`
            DefaultGoal float64 `yaml:"defaultGoal"`
            Projects    []int   `yaml:"projects"`
}
type PP struct {
            DefaultGoal int `yaml:"defaultGoal"`
            Project     int `yaml:project`
}

func main() {
    var cfg Config
    // init cfg somehow
    for space, value := range cfg.Workspaces {
        switch space {
        case "ibm": // convert `value` to IBM struct
        case "pp": // convert `value` to PP struct
    }
}

如果你想根据 Workspace 名称解组为特定结构,你可以试试这个方法。 (使用 json 时通常不需要额外的编组步骤。更多 here). Working example here

package main

import (
    "log"

    "gopkg.in/yaml.v2"
)

type Config struct {
    DefaultTimeout   float64 `yaml:"defaultTimeout"`
    DefaultWorkspace string  `yaml:"defaultWorkspace"`
    Workspaces       map[string]interface{}
}

type PP struct {
    DefaultGoal int `yaml:"defaultGoal"`
    Project     int `yaml:"project"`
}

type IBM struct {
    Client      int     `yaml:"client"`
    DefaultGoal float64 `yaml:"defaultGoal"`
    Projects    []int   `yaml:"projects"`
}

func main() {
    yamlData := `defaultTimeout: 0.25
defaultWorkspace: ibm
workspaces:
ibm:
    client: 47943938
    defaultGoal: 27.5
    projects:
    - 159929907
    - 160046030
    - 160064503
pp:
    defaultGoal: 5.5
    project: 160064503`

    var c Config
    if err := yaml.Unmarshal([]byte(yamlData), &c); err != nil {
        panic(err)
    }

    for space, value := range c.Workspaces {
        bs, err := yaml.Marshal(value)
        if err != nil {
            panic(err)
        }

        switch space {
        case "ibm":
            var i IBM
            if err := yaml.Unmarshal(bs, &i); err != nil {
                panic(err)
            }

            log.Printf("IBM value: %v", i)

        case "pp":
            var p PP
            if err := yaml.Unmarshal(bs, &p); err != nil {
                panic(err)
            }

            log.Printf("PP value: %v", p)
        }
    }
}