gopkg.in/yaml.v3 是golang中最常用的yaml工具包,用此包解析yaml文件到结构体存在三个问题。
- yaml文件中的配置项首字母不能大写,配置项名字要求比较严格。
- 没有默认值。
- 没有数值校验。
解决思路
- 把yaml文件解析成map对象在通过json转成struct,利用json的的特性来控制yaml文件中字段名字。
- 通过github.com/creasty/def… 这个工具添加默认配置。
- 通过github.com/dealancer/v… 这个工具添加校验。 站在巨人肩上干活就是好又快。
代码实现
import (
"encoding/json"
"io/ioutil"
"reflect"
"github.com/creasty/defaults"
"gopkg.in/dealancer/validate.v2"
"gopkg.in/yaml.v3"
)
type YamlConfig struct {
mapdata map[string]interface{}
cfg interface{} //指针类型
}
func NewYamlConfig(cfg interface{}) (*YamlConfig, error) {
rfv := reflect.ValueOf(cfg)
if err := ValidatePtr(&rfv); err != nil {
return nil, err
}
return &YamlConfig{cfg: cfg}, nil
}
// read and yaml unmarshal
func (this *YamlConfig) read(in string) error {
bytes, err := ioutil.ReadFile(in)
if err != nil {
return err
}
if err := yaml.Unmarshal(bytes, &this.mapdata); err != nil {
return err
}
return nil
}
// json to config obj
// use json tag not yaml
func (this *YamlConfig) jsonDecode() error {
bytes, err := json.Marshal(this.mapdata)
if err != nil {
return err
}
// fmt.Println(string(bt), err)
if err := json.Unmarshal(bytes, this.cfg); err != nil {
return err
}
return nil
}
func (this *YamlConfig) doDefault() error {
return defaults.Set(this.cfg)
}
func (this *YamlConfig) doValide() error {
return validate.Validate(this.cfg)
}
func Load(configFile string, in interface{}) error {
cfg, err := NewYamlConfig(in)
if err != nil {
return err
}
if err := cfg.read(configFile); err != nil {
return err
}
if err := cfg.jsonDecode(); err != nil {
return err
}
if err := cfg.doDefault(); err != nil {
return err
}
if err := cfg.doValide(); err != nil {
return err
}
return nil
}