如何使用结构体迭代遍历 yml 部分?

huangapple go评论96阅读模式
英文:

How to iterate over yml sections with structs?

问题

我使用viper。我正在尝试从带有yml-config的结构体中获取信息。

type Config struct {
    Account User `mapstructure:"user"`    	
}

type User struct {
    Name     string    `mapstructure:"name"`
    Contacts []Contact `mapstructure:"contact"`
}

type Contact struct {
    Type  string `mapstructure:"type"`
    Value string `mapstructure:"value"`
}

func Init() *Config {
    conf := new(Config)

    viper.SetConfigType("yaml")
    viper.ReadInConfig()
    ...
    viper.Unmarshal(conf)
    return conf
}

...
config := Init()
...
for _, contact := range config.Account.Contacts {
    type := contact.Type
    value := contact.Value
}

config.yml文件如下:

user:
  name: John
  contacts:
    email:
      type: email
      value: test@test.com
    skype:
      type: skype
      value: skypeacc

你能像这样获取结构体的项吗?我无法像那样获取联系人数据。这种情况可能吗?

英文:

I use viper. I'm trying to get info from structs with yml-config.

type Config struct {
	Account       User           `mapstructure:"user"`    	
}

type User struct {
	Name       string           `mapstructure:"name"`
	Contacts   []Contact	    `mapstructure:"contact"`
}

type Contact struct {
	Type      	  string          `mapstructure:"type"`
	Value         string          `mapstructure:"value"`
}

func Init() *Config {
	conf := new(Config)

	viper.SetConfigType("yaml")
	viper.ReadInConfig()
    ...
	viper.Unmarshal(conf)
	return conf
}

...
config := Init()
...
for _, contact := range config.Account.Contacts {
   type := contact.type
   vlaue := contact.value
}

And config.yml

user:
  name: John
  contacts:
    email:
      type: email
      value: test@test.com
    skype:
      type: skype
      value: skypeacc

Can I get structure items like this? I could not get contact data like that. Is it possible?

答案1

得分: 1

如果我理解你的目标正确,并且根据你提供的for循环,你实际上需要一个YAML的序列,也就是一个数组。所以你的最终YAML文件应该如下所示:

user:
  name: John
  contacts:
      - type: email
        value: test@test.com
      - type: skype
        value: skypeacc
      - type: email
        value: joe@example.com

此外,你在Contacts切片的标签中有一个拼写错误。它应该与YAML键匹配:

type User struct {
	Name     string    `mapstructure:"name"`
	Contacts []Contact `mapstructure:"contacts"`
}

如果你希望保留原始的YAML文件结构,你必须为每个YAML键提供一个标签(和相应的结构字段),这样就无法直接循环遍历它,因为emailskype会被解析为结构字段。原始YAML文件的结构示例如下:

type Config struct {
	Account User `mapstructure:"user"`
}

type User struct {
	Name     string   `mapstructure:"name"`
	Contacts Contacts `mapstructure:"contacts"`
}

type Contacts struct {
	Email Contact `mapstructure:"email"`
	Skype Contact `mapstructure:"skype"`
}

type Contact struct {
	Type  string `mapstructure:"type"`
	Value string `mapstructure:"value"`
}
英文:

If I'm getting right what you want to achieve, and based on the for loop you provided;

  • What you actually need is a YAML sequence, which is an array. So your final YAML file should look like;
user:
  name: John
  contacts:
      - type: email
        value: test@test.com
      - type: skype
        value: skypeacc
      - type: email
        value: joe@example.com
  • Also, you have a typo in your tag on Contacts slice. It should match the YAML key;
type User struct {
   Name     string    `mapstructure:"name"`
   Contacts []Contact `mapstructure:"contacts"`
}

If you wish to keep the original YAML file structure you have to provide a tag (and the corresponding struct field) for each YAML key, so looping over it wouldn't be possible out of the box, because email and skype are parsed as struct fields. An example of the struct for the original YAML file would be;

type Config struct {
	Account User `mapstructure:"user"`
}

type User struct {
	Name     string   `mapstructure:"name"`
	Contacts Contacts `mapstructure:"contacts"`
}

type Contacts struct {
	Email Contact `mapstructure:"email"`
	Skype Contact `mapstructure:"skype"`
}

type Contact struct {
	Type  string `mapstructure:"type"`
	Value string `mapstructure:"value"`
}

答案2

得分: 0

我认为唯一的重要问题是,在你的数据结构中,你将Contacts声明为一个列表,但在你的YAML文件中,它是一个字典。如果你按照以下方式组织你的输入文件:

user:
  name: John
  contacts:
    - type: email
      value: test@test.com
    - type: skype
      value: skypeacc

那么你可以这样读取它:

package main

import (
	"fmt"

	"github.com/spf13/viper"
)

type Config struct {
	User User
}

type User struct {
	Name     string
	Contacts []Contact
}

type Contact struct {
	Type  string
	Value string
}

func main() {
	var cfg Config

	viper.SetConfigName("config")
	viper.AddConfigPath(".")
	err := viper.ReadInConfig()
	if err != nil {
		panic(err)
	}
	viper.Unmarshal(&cfg)
	fmt.Println("user: ", cfg.User.Name)
	for _, contact := range cfg.User.Contacts {
		fmt.Println("  ", contact.Type, ": ", contact.Value)
	}
}

上面的代码可以直接运行;你只需要将它放入一个文件中并构建它。当我运行上面的示例时,我得到的输出是:

user:  John
   email :  test@test.com
   skype :  skypeacc
英文:

I think the only significant problem is that in your data structures you've declared Contacts as a list, but in your YAML file it's a dictionary. If you structure your input file like this:

user:
  name: John
  contacts:
    - type: email
      value: test@test.com
    - type: skype
      value: skypeacc

Then you can read it like this:

package main

import (
	"fmt"

	"github.com/spf13/viper"
)

type Config struct {
	User User
}

type User struct {
	Name     string
	Contacts []Contact
}

type Contact struct {
	Type  string
	Value string
}

func main() {
	var cfg Config

	viper.SetConfigName("config")
	viper.AddConfigPath(".")
	err := viper.ReadInConfig()
	if err != nil {
		panic(err)
	}
	viper.Unmarshal(&cfg)
	fmt.Println("user: ", cfg.User.Name)
	for _, contact := range cfg.User.Contacts {
		fmt.Println("  ", contact.Type, ": ", contact.Value)
	}
}

The above code is runnable as-is; you should just be able to drop it
into a file and build it. When I run the above example, I get as
output:

user:  John
   email :  test@test.com
   skype :  skypeacc

huangapple
  • 本文由 发表于 2021年7月16日 17:53:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/68407017.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定