Golang中YAML.v3为何不基于String()方法序列化结构体?
解决Go枚举类型序列化友好字符串的问题
你的代码中stringer工具已正确生成String()方法,但输出数字的问题主要源于两点:fmt输出未正确调用String()(大概率是生成的代码未被纳入编译流程),以及yaml序列化默认不识别String()方法。
步骤1:确保String()方法被正确编译运行
stringer生成的代码需要被包含到编译环节中:
- 执行
go generate命令生成枚举的String()实现代码 - 直接运行
go run main.go,Go会自动包含同目录下所有Go文件,确保生成的代码被编译
若生成代码无误,fmt.Printf("%+v")会输出{Engine:Docker}——因为Engine类型实现了fmt.Stringer接口,%+v格式化会自动调用其String()方法。
步骤2:实现yaml序列化的友好字符串
yaml.v3默认通过反射序列化自定义类型的底层值(此处为int),不会自动调用String()方法。需为Engine类型实现yaml.Marshaler接口:
func (e Engine) MarshalYAML() (interface{}, error) { return e.String(), nil }
添加该方法后,yaml序列化会输出友好的字符串形式。
可选优化:统一枚举常量命名
当前枚举中engineUnknown和engineDone为小写开头,--trimprefix=Engine不会处理这类命名,导致生成的字符串是engineUnknown而非Unknown。建议统一使用大写开头的命名:
const ( EngineUnknown Engine = iota // must be first EngineDocker EngineDone // must be last )
重新执行go generate后,String()方法会返回Unknown、Docker、Done,命名更规范。
修改后的完整代码
package main import ( "fmt" "gopkg.in/yaml.v3" ) type Job struct { Engine Engine `json:"Engine" yaml:"Engine"` } //go:generate stringer -type=Engine --trimprefix=Engine type Engine int const ( EngineUnknown Engine = iota // must be first EngineDocker EngineDone // must be last ) func (e Engine) MarshalYAML() (interface{}, error) { return e.String(), nil } func main() { j := Job{Engine: EngineDocker} fmt.Printf("%+v\n\n", j) out, _ := yaml.Marshal(j) fmt.Println(string(out)) }
执行go generate后运行,输出会符合预期:
{Engine:Docker} Engine: Docker
内容的提问来源于stack exchange,提问作者aronchick
相关产品推荐
相关产品推荐

