将配置结构加载到 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)
}
}
}
所以我想在我的程序中加载一个 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)
}
}
}