自定义结构的 UnmarshalYAML 接口的实现
Implementation of the UnmarshalYAML Interface for a custom Struct
我有以下结构、接口和函数:
type FruitBasket struct {
Capacity int `yaml:"capacity"`
Fruits []Fruit
}
type Fruit interface {
GetFruitName() string
}
type Apple struct {
Name string `yaml:"name"`
}
func (apple *Apple) GetFruitName() string {
return apple.Name
}
type tmpFruitBasket []map[string]yaml.Node
func (fruitBasket *FruitBasket) UnmarshalYAML(value *yaml.Node) error {
var tmpFruitBasket tmpFruitBasket
if err := value.Decode(&tmpFruitBasket); err != nil {
return err
}
fruits := make([]Fruit, 0, len(tmpFruitBasket))
for i := 0; i < len(tmpFruitBasket); i++ {
for tag, node := range tmpFruitBasket[i] {
switch tag {
case "Apple":
apple := &Apple{}
if err := node.Decode(apple); err != nil {
return err
}
fruits = append(fruits, apple)
default:
return errors.New("Failed to interpret the fruit of type: \"" + tag + "\"")
}
}
}
fruitBasket.Fruits = fruits
return nil
}
使用这段代码,我可以解析以下 yaml 文件:
FruitBasket:
- Apple:
name: "apple1"
- Apple:
name: "apple2"
主要函数如下所示:
func main() {
data := []byte(`
FruitBasket:
- Apple:
name: "apple1"
- Apple:
name: "apple2"
`)
fruitBasket := new(FruitBasket)
err := yaml.Unmarshal(data, &fruitBasket)
if err != nil {
log.Fatalf("error: %v", err)
}
for i := 0; i < len(fruitBasket.Fruits); i++ {
switch fruit := fruitBasket.Fruits[i].(type) {
case *Apple:
fmt.Println("The name of the apple is: " + fruit.GetFruitName())
}
}
}
但是,我无法解析以下 yaml 字符串:
FruitBasket:
capacity: 2
- Apple:
name: "apple1"
- Apple:
name: "apple2"
对于这个字符串,我得到以下错误:error: yaml: did not find expected key
。
我必须如何调整 UnmarshalYAML 接口的实现,才能同时解析后面的字符串?
您的 YAML 无效。每个 YAML 值都是标量、序列或映射。
在 capacity:
,YAML 处理器决定此级别包含映射,因为它看到第一个键。现在,在下一行,它看到 - Apple:
,一个序列项。这在映射级别内无效;它需要下一个键,因此给你一个错误 did not find expected key
.
结构的修复可能如下所示:
FruitBasket:
capacity: 2
items:
- Apple:
name: "apple1"
- Apple:
name: "apple2"
请注意,序列项仍然出现在同一级别,但是由于 items:
没有内联值,这些项被解析为一个序列,该序列是键 items
的值.同一缩进级别的另一个键将结束序列。
然后您可以将其加载到如下类型中:
type tmpFruintBasket struct {
Capacity int
Items []map[string]yaml.Node
}
我有以下结构、接口和函数:
type FruitBasket struct {
Capacity int `yaml:"capacity"`
Fruits []Fruit
}
type Fruit interface {
GetFruitName() string
}
type Apple struct {
Name string `yaml:"name"`
}
func (apple *Apple) GetFruitName() string {
return apple.Name
}
type tmpFruitBasket []map[string]yaml.Node
func (fruitBasket *FruitBasket) UnmarshalYAML(value *yaml.Node) error {
var tmpFruitBasket tmpFruitBasket
if err := value.Decode(&tmpFruitBasket); err != nil {
return err
}
fruits := make([]Fruit, 0, len(tmpFruitBasket))
for i := 0; i < len(tmpFruitBasket); i++ {
for tag, node := range tmpFruitBasket[i] {
switch tag {
case "Apple":
apple := &Apple{}
if err := node.Decode(apple); err != nil {
return err
}
fruits = append(fruits, apple)
default:
return errors.New("Failed to interpret the fruit of type: \"" + tag + "\"")
}
}
}
fruitBasket.Fruits = fruits
return nil
}
使用这段代码,我可以解析以下 yaml 文件:
FruitBasket:
- Apple:
name: "apple1"
- Apple:
name: "apple2"
主要函数如下所示:
func main() {
data := []byte(`
FruitBasket:
- Apple:
name: "apple1"
- Apple:
name: "apple2"
`)
fruitBasket := new(FruitBasket)
err := yaml.Unmarshal(data, &fruitBasket)
if err != nil {
log.Fatalf("error: %v", err)
}
for i := 0; i < len(fruitBasket.Fruits); i++ {
switch fruit := fruitBasket.Fruits[i].(type) {
case *Apple:
fmt.Println("The name of the apple is: " + fruit.GetFruitName())
}
}
}
但是,我无法解析以下 yaml 字符串:
FruitBasket:
capacity: 2
- Apple:
name: "apple1"
- Apple:
name: "apple2"
对于这个字符串,我得到以下错误:error: yaml: did not find expected key
。
我必须如何调整 UnmarshalYAML 接口的实现,才能同时解析后面的字符串?
您的 YAML 无效。每个 YAML 值都是标量、序列或映射。
在 capacity:
,YAML 处理器决定此级别包含映射,因为它看到第一个键。现在,在下一行,它看到 - Apple:
,一个序列项。这在映射级别内无效;它需要下一个键,因此给你一个错误 did not find expected key
.
结构的修复可能如下所示:
FruitBasket:
capacity: 2
items:
- Apple:
name: "apple1"
- Apple:
name: "apple2"
请注意,序列项仍然出现在同一级别,但是由于 items:
没有内联值,这些项被解析为一个序列,该序列是键 items
的值.同一缩进级别的另一个键将结束序列。
然后您可以将其加载到如下类型中:
type tmpFruintBasket struct {
Capacity int
Items []map[string]yaml.Node
}