我正在嘗試將以下 YAML 資料解組為 Go 結構。
資料格式如下:
fetchers:
- type: "aws"
config:
omega: "lul"
- type: "kubernetes"
config:
foo: "bar"
根據型別欄位,我想確定是否將配置欄位解組為awsConfig或kubernetesConfig結構。
我當前的代碼如下所示(使用“gopkg.in/yaml.v2”):
type kubernetesConfig struct {
foo string `yaml:"foo"`
}
type awsConfig struct {
omega string `yaml:"omega"`
}
var c struct {
Fetchers []struct {
Type string `yaml:"type"`
Config interface{} `yaml:"config"`
} `yaml:"fetchers"`
}
err := yaml.Unmarshal(data, &c)
if err != nil {
log.Fatal(err)
}
for _, val := range c.Fetchers {
switch val.Type {
case "kubernetes":
conf := val.Config.(kubernetesConfig)
fmt.Println(conf.foo)
case "aws":
conf := val.Config.(awsConfig)
fmt.Println(conf.omega)
default:
log.Fatalf("No matching type, was type %v", val.Type)
}
}
操場上的代碼:https : //go.dev/play/p/klxOoHMCtnG
目前它被解組為map[interface {}]interface {},不能轉換為上述結構之一。
錯誤:
panic: interface conversion: interface {} is map[interface {}]interface {}, not main.awsConfig\
我是否必須使用自定義 UnmarshalYAML 函式實作 YAML 包的 Unmarshaler 介面才能完成此操作?
uj5u.com熱心網友回復:
通過實作 Unmarshaler 介面找到了解決方案:
type Fetcher struct {
Type string `yaml:"type"`
Config interface{} `yaml:"config"`
}
// Interface compliance
var _ yaml.Unmarshaler = &Fetcher{}
func (f *Fetcher) UnmarshalYAML(unmarshal func(interface{}) error) error {
var t struct {
Type string `yaml:"type"`
}
err := unmarshal(&t)
if err != nil {
return err
}
f.Type = t.Type
switch t.Type {
case "kubernetes":
var c struct {
Config kubernetesConfig `yaml:"config"`
}
err := unmarshal(&c)
if err != nil {
return err
}
f.Config = c.Config
case "aws":
var c struct {
Config awsConfig `yaml:"config"`
}
err := unmarshal(&c)
if err != nil {
return err
}
f.Config = c.Config
}
return nil
}
uj5u.com熱心網友回復:
這種型別的任務(您想要延遲解組的地方)與json.RawMessage與此類示例的作業方式非常相似。
yaml 包沒有類似的機制RawMessage- 但這種技術可以很容易地復制,如下所述:
type RawMessage struct {
unmarshal func(interface{}) error
}
func (msg *RawMessage) UnmarshalYAML(unmarshal func(interface{}) error) error {
msg.unmarshal = unmarshal
return nil
}
// call this method later - when we know what concrete type to use
func (msg *RawMessage) Unmarshal(v interace{}) error {
return msg.unmarshal(v)
}
因此,在您的情況下利用這一點:
var fs struct {
Configs []struct {
Type string `yaml:"type"`
Config RawMessage `yaml:"config"` // delay unmarshaling
} `yaml:"fetchers"`
}
err = yaml.Unmarshal([]byte(data), &fs)
if err != nil {
return
}
并基于配置“型別”(aws或kubernetes),您最終可以將其解組RawMessage為正確的具體型別:
aws := awsConfig{} // concrete type
err = c.Config.Unmarshal(&aws)
或者:
k8s := kubernetesConfig{} // concrete type
err = c.Config.Unmarshal(&k8s)
此處的作業示例:https : //go.dev/play/p/wsykOXNWk3H
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/407114.html
標籤:
上一篇:為什么Golangstring.BuilderString()可以在沒有reflect.StringHeader的情況下將[]byte轉換為slice?
