golang使用 viper 無需設置 mapstructure tag 根據配置文件后綴 自動返序列化到結構
解決結構有下劃線的字段解析不成功問題
viper 正常加載配置文件
golang viper 其中可以用來 查找、加載和反序列化JSON、TOML、YAML、HCL、INI、envfile和格式的配置文件
配置文件 test_toml.toml
http_addr = ":8082"
grpc_addr = ":8083"
jaeger_url= "http://localhost:14268/api/traces"
tracing= true
golang代碼
type ConfigTest struct {HttpAddr string `json:"http_addr" toml:"http_addr" yaml:"http_addr"`GrpcAddr string `json:"grpc_addr" toml:"grpc_addr" yaml:"grpc_addr"`JaegerUrl string `json:"jaeger_url" toml:"jaeger_url" yaml:"jaeger_url" mapstructure:"jaeger_url"`Tracing bool `toml:"tracing" json:"tracing" yaml:"tracing" ` // opentelemetry tracing
}// jaeger 加載配置文件
func TestSourceFile_Unmarshal(t *testing.T) {filePath := "./test_toml.toml"viper.SetConfigFile(filePath)if err := viper.ReadInConfig(); err != nil {t.Error(err)}c := &ConfigTest{}if err := viper.Unmarshal(c); err != nil {t.Error(err)}logger.Infow("Unmarshal file sucess", "v", c)
}
打印返序列化的配置結構
{"level":"info","ts":"2023-08-27T21:35:27.041+0800","caller":"config/source_file_test.go:31","msg":"Unmarshal file sucess","v":{"http_addr":"","grpc_addr":"","jaeger_url":"http://localhost:14268/api/traces","tracing":true}}
可以看到帶下劃線的字段,不加 mapstructure 標簽,是不會反序列化
不加 mapstructure tag實現自動反序列化
查看viper Unmarshal 代碼
func (v *Viper) Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error {return decode(v.AllSettings(), defaultDecoderConfig(rawVal, opts...))
}
func decode(input interface{}, config *mapstructure.DecoderConfig) error {decoder, err := mapstructure.NewDecoder(config)if err != nil {return err}return decoder.Decode(input)
}
func NewDecoder(config *DecoderConfig) (*Decoder, error) {if config.TagName == "" {config.TagName = "mapstructure"}// ...
}
- 從代碼看出 Viper使用的是 github.com/mitchellh/mapstructure來解析值
- mapstructure 用于將通用的map[string]interface{}解碼到對應的 Go 結構體中
- 默認情況下,mapstructure 使用結構體中字段的名稱做這個映射,不區分大小寫,比如 Name 字段可以映射到
name、NAME、NaMe 等等 - 如果沒有指定 tagName ,則默認為 mapstructure,這也是為什么帶下劃線的字段不加 mapstructure
標簽無法解析的原因 - viper 中Unmarshal的第二個參數是可以指定 DecoderConfigOption 的,從而可以指定 tagName
viper根據文類型件自動解碼到結構
讀取文件后綴比如 toml
根據后綴設置 tagName
調用 viper.Unmarshal解析
func TestSourceFile_Unmarshal1(t *testing.T) {filePath := "./test_toml.toml"c := &ConfigTest{}if err := viperUnmarshal(c, filePath); err != nil {t.Error(err)}logger.Infow("Unmarshal file sucess", "v", c)
}func viperUnmarshal(v interface{}, configPath string) error {var tagName stringext := filepath.Ext(configPath)if len(ext) > 1 {tagName = ext[1:]}// set decode tag_name, default is mapstructuredecoderConfigOption := func(c *mapstructure.DecoderConfig) {c.TagName = tagName}cViper := viper.New()cViper.SetConfigFile(configPath)if err := cViper.ReadInConfig(); err != nil {return err}return cViper.Unmarshal(v, decoderConfigOption)
}