BadZen
BadZen

Reputation: 4274

Go YAML parser failing silently

I'm trying to get simple YAML parsing in go working with gopkg.in/yaml.v2.

From the documentation:

Maps and pointers (to a struct, string, int, etc) are accepted as out values. If an internal pointer within a struct is not initialized, the yaml package will initialize it if necessary for unmarshalling the provided data. The out parameter must not be nil.

The type of the decoded values should be compatible with the respective values in out. If one or more values cannot be decoded due to a type mismatches, decoding continues partially until the end of the YAML content, and a *yaml.TypeError is returned with details for all missed values.

Note the important bits here: "pointer within struct initialized if nec'y", and "yaml.TypeError returned if a value can't be decoded".

Now:

package main

import (
    "fmt"
    "gopkg.in/yaml.v2"
)

type YamlTypeA struct {
    D string    `yaml: "d"`
    E string    `yaml: "e"`
}

type YamlTypeB struct {
    F string    `yaml: "f"`
}

type YamlTypeC struct {
    TypeA   *YamlTypeA      `yaml: "a"`
    TypeB   []YamlTypeB `yaml: "b"`
}

func main() {
    var yamlObj YamlTypeC

    text := []byte(`
---
a:  
   d: foo 
   e: bar
b: [{f: "fails"},
    {f: "completely"}]
`)

    err := yaml.Unmarshal(text,&yamlObj)
    if err != nil {
        fmt.Println(err.Error())
        return
    }
    fmt.Println("OK")
    fmt.Printf("TypeA.D: %s\n", yamlObj.TypeA.D)
    fmt.Printf("I have %d TypeB\n", len(yamlObj.TypeB))
}

yields

 OK
 panic: runtime error: invalid memory address or nil pointer dereference
 [signal 0xb code=0x1 addr=0x0 pc=0x4014b3]

which appears to violate the promises made in the documentation jointly. If I make the nested YamlTypeA immediate instead of a pointer, the result is that the output value is not touched, still no error:

 OK
 TypeA.D: 
 I have 0 TypeB

What gives here? Is it just broken / poorly documented? How can you get nested struct values to parse out of YAML? (Using maps of maps is cumbersome and not at all a solution here.)

Upvotes: 2

Views: 1559

Answers (1)

Mr_Pink
Mr_Pink

Reputation: 109397

You have spaces in your struct tags, so they're being ignored:

type YamlTypeA struct {
    D string `yaml:"d"`
    E string `yaml:"e"`
}

type YamlTypeB struct {
    F string `yaml:"f"`
}

type YamlTypeC struct {
    TypeA *YamlTypeA  `yaml:"a"`
    TypeB []YamlTypeB `yaml:"b"`
}

Upvotes: 5

Related Questions