【问题标题】:Casting unmarshaled yaml interface{} into actual struct将未编组的 yaml interface{} 转换为实际结构
【发布时间】:2020-11-05 00:16:10
【问题描述】:

我有以下问题:我以 yaml 形式接收信息,它可以有 2 种配置 - 单个字符:

Character:
  Name: Stackoverflow
  Type: Awesome

或者在多个字符的切片中带有可选的朋友切片字段:

Character:
- Name: Stackoverflow
  Type: Awesome
  Friends: [Ben, John]
- Name: Facebook
  Type: Ok

因为我不知道哪个配置会到达,所以我尝试将 yaml 解组为 interface{},然后将其转换为其中一个结构,但没有成功:

type CharacterConfig struct{
Name    string      `yaml:"Name"`
Type    string      `yaml:"Type"`
Friends []string    `yaml:"Friends,omitempty"`


var d interface{}
err := yaml.Unmarshal([]byte(yamlData), &d)
if err != nil {
    panic(err)
}

res, ok := d.(CharacterConfig)
if ok {
    fmt.Println("CharacterConfig are ok")
}

res, ok := d.([]CharacterConfig)
if ok {
    fmt.Println("[]CharacterConfig are ok")
}

但是我没有收到任何打印...当我调试时,我可以看到解组到接口的工作,但没有铸件。 我知道我可以直接解组到结构中,但我不明白我所做的一切没有奏效。

【问题讨论】:

  • 术语说明:Go 根本没有类型转换。你说的是类型转换。

标签: go struct yaml slice


【解决方案1】:

解组到interface{} 不会神奇地猜测您想要自定义CharacterConfig 结构中的结果。将 YAML 解组为 interface{} 将使用 map[interface{}]interface{} 表示对象,并使用 []interface{} 递归表示列表/数组。

因此上面的类型断言产生ok = false,因为存储在其中的值是interfaces{} 的映射或切片。您可以键入 assert 这些类型,并且断言会成功,但您不会更接近将这些值作为您的结构。

另请注意,您的输入 YAML 需要另一个包装层:

type Character struct {
    CC CharacterConfig `yaml:"Character"`
}

type CharacterList struct {
    CCs []CharacterConfig `yaml:"Character"`
}

因此,一种简单的方法是首先尝试解组为 Character 类型的值,如果成功,您就完成了。如果没有,请尝试再次解组,这次是 CharacterList

这是一个执行此操作的示例代码:

func unmarshal(data []byte) {
    var c Character
    err := yaml.Unmarshal(data, &c)
    if err == nil {
        fmt.Printf("It's Character: %+v\n", c)
        return
    }

    var cl CharacterList
    err = yaml.Unmarshal(data, &cl)
    if err != nil {
        panic(err)
    }
    fmt.Printf("It's CharacterList: %+v\n", cl)
}

像这样测试它:

func main() {
    unmarshal([]byte(src))
    unmarshal([]byte(src2))
}

const src = `Character:
  Name: Stackoverflow
  Type: Awesome`

const src2 = `Character:
- Name: Stackoverflow
  Type: Awesome
  Friends: [Ben, John]
- Name: Facebook
  Type: Ok`

输出将是(在Go Playground 上尝试):

It's Character: {CC:{Name:Stackoverflow Type:Awesome Friends:[]}}
It's CharacterList: {CCs:[{Name:Stackoverflow Type:Awesome Friends:[Ben John]} {Name:Facebook Type:Ok Friends:[]}]}

【讨论】:

    【解决方案2】:

    与您所做的类似,但没有界面:

    type CharacterConfig struct{
        Name    string      `yaml:"Name"`
        Type    string      `yaml:"Type"`
        Friends []string    `yaml:"Friends,omitempty"`
    }
    
    var a CharacterConfig
    var b []CharacterConfig
    
    err := yaml.Unmarshal([]byte(yamlData), &a)
    if err == nil {
        // a is valid format
    }
    
    err = yaml.Unmarshal([]byte(yamlData), &b)
    if err == nil {
        // b is valid format
    }
    

    【讨论】:

      猜你喜欢
      • 2021-08-06
      • 2018-12-25
      • 2020-09-23
      • 1970-01-01
      • 2015-06-22
      • 1970-01-01
      • 1970-01-01
      • 2017-04-05
      • 1970-01-01
      相关资源
      最近更新 更多