You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Go中优雅读取不同子类型的YAML(K8s CRD场景)

优化多文档YAML的GetAll泛型函数,去除冗余解码与类型转换

原代码在处理多文档YAML时,存在多次解码、冗余类型转换的问题,以下是优化后的实现,代码更简洁清晰:

优化后的代码

package main

import (
	"bytes"
	"fmt"

	"gopkg.in/yaml.v3"
)

const yamldata = `
kind: Kind1
spec1: AAA
---
kind: Kind2
spec2: BBB
`

type Meta struct {
	Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
}
type Kind1 struct {
	Meta  `json:",inline" yaml:",inline"`
	Spec1 string `json:"spec1,omitempty" yaml:"spec1,omitempty"`
}
type Kind2 struct {
	Meta  `json:",inline" yaml:",inline"`
	Spec2 string `json:"spec2,omitempty" yaml:"spec2,omitempty"`
}

// CRDKind 定义CRD类型的接口,用于获取对应的Kind标识
type CRDKind interface {
	GetKind() string
}

func (k *Kind1) GetKind() string {
	return "Kind1"
}

func (k *Kind2) GetKind() string {
	return "Kind2"
}

func GetAll[T CRDKind](yamldata string) ([]T, error) {
	var result []T
	dec := yaml.NewDecoder(bytes.NewBufferString(yamldata))

	for {
		var item T
		err := dec.Decode(&item)
		if err != nil {
			if err.Error() == "EOF" {
				return result, nil
			}
			return nil, err
		}

		// 校验当前文档的Kind是否匹配目标类型
		if item.GetKind() == item.Meta.Kind {
			result = append(result, item)
		}
	}
}

func main() {
	kind1s, err := GetAll[Kind1](yamldata)
	if err != nil {
		fmt.Printf("获取Kind1实例失败: %v\n", err)
		return
	}
	fmt.Printf("%+v\n", kind1s[0])

	kind2s, err := GetAll[Kind2](yamldata)
	if err != nil {
		fmt.Printf("获取Kind2实例失败: %v\n", err)
		return
	}
	fmt.Printf("%+v\n", kind2s[0])
}

优化说明

  1. 引入接口规范:定义CRDKind接口,让每个CRD类型实现GetKind()方法,明确自身对应的Kind标识,避免硬编码判断。
  2. 简化解码流程:直接创建泛型目标类型的实例进行解码,无需先解码为yaml.Node再二次解码,减少冗余操作。
  3. 清晰的类型校验:通过对比实例的Meta.Kind和自身的GetKind()结果,判断是否为目标类型,逻辑直观。
  4. 完善错误处理:明确区分EOF(文档处理完成)和其他解码错误,返回合理的错误信息,避免原代码中忽略错误的问题。
  5. 移除冗余转换:删除原代码中不必要的类型断言和switch分支,代码结构更简洁。

内容的提问来源于stack exchange,提问作者SkyN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 12:57:59