Go YAML解析器默默失败

huangapple go评论83阅读模式
英文:

Go YAML parser failing silently

问题

我正在尝试使用gopkg.in/yaml.v2在Go中实现简单的YAML解析。

根据文档

>可以接受映射和指针(指向结构体、字符串、整数等)作为输出值。如果结构体内部的指针未初始化,YAML包将在必要时进行初始化,以便对提供的数据进行解组。输出参数不能为nil。
>
>解码后的值的类型应与输出中的相应值兼容。如果由于类型不匹配而无法解码一个或多个值,则解码将部分继续,直到YAML内容的末尾,并返回一个*yaml.TypeError,其中包含所有未解码的值的详细信息。

请注意这里的重要部分:“如果需要,初始化结构体内部的指针”和“如果无法解码值,则返回yaml.TypeError”。

现在看一下代码:

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))
}

运行结果为:

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

这似乎违反了文档中的承诺。如果我将嵌套的YamlTypeA改为立即值而不是指针,结果是输出值不会被修改,但仍然没有错误:

OK
TypeA.D: 
I have 0 TypeB

这是怎么回事?它只是有问题/文档不完善吗?如何从YAML中解析嵌套的结构体值?(在这里使用映射的映射很麻烦,也不是解决方案。)

英文:

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.)

答案1

得分: 5

你的结构标签中有空格,所以它们被忽略了:

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"`
}
英文:

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"`
}

huangapple
  • 本文由 发表于 2015年12月16日 04:44:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/34299049.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定