为了账号安全,请及时绑定邮箱和手机立即绑定

为什么 YAML.v3 不编组基于 golang 中的 String() 的结构?

为什么 YAML.v3 不编组基于 golang 中的 String() 的结构?

Go
喵喔喔 2023-02-21 12:54:46
我有一个包含基于枚举的类型的结构。我正在尝试将其呈现为用户友好的字符串。这是最小可行代码:package mainimport (    "fmt"    "gopkg.in/yaml.v3")type Job struct {    Engine Engine `json:"Engine" yaml:"Engine"`}//go:generate stringer -type=Engine --trimprefix=Enginetype Engine intconst (    engineUnknown Engine = iota // must be first    EngineDocker    engineDone // must be last)func main() {    j := Job{Engine: EngineDocker}    fmt.Printf("%+v\n\n", j)    out, _ := yaml.Marshal(j)    fmt.Println(string(out))}这是生成的代码:// Code generated by "stringer -type=Engine --trimprefix=Engine"; DO NOT EDIT.package mainimport "strconv"func _() {    // An "invalid array index" compiler error signifies that the constant values have changed.    // Re-run the stringer command to generate them again.    var x [1]struct{}    _ = x[engineUnknown-0]    _ = x[EngineDocker-1]    _ = x[engineDone-2]}const _Engine_name = "engineUnknownDockerengineDone"var _Engine_index = [...]uint8{0, 13, 19, 29}func (i Engine) String() string {    if i < 0 || i >= Engine(len(_Engine_index)-1) {        return "Engine(" + strconv.FormatInt(int64(i), 10) + ")"    }    return _Engine_name[_Engine_index[i]:_Engine_index[i+1]]}这是输出:{Engine:1}Engine: 1这是我想要的输出:{Engine:Docker}Engine: Docker我认为生成文件中的 String() 可以完成此操作。有什么办法吗?谢谢!
查看完整描述

1 回答

?
隔江千里

TA贡献1906条经验 获得超10个赞

yaml封送拆收器不使用String方法。相反,YAML使用 encoding.TextMarshalerencoding.TextUnmarshaler接口。实际上,所有其他编解码器方案——JSON、XML、TOML 等——都使用这些接口来读取/写入值。因此,如果您为您的类型实现这些方法,您将免费获得所有其他编解码器。

这是一个如何为您的枚举制作人类可读编码的示例:https://go.dev/play/p/pEcBmAM-oZJ

type Engine int


const (

    engineUnknown Engine = iota // must be first

    EngineDocker

    engineDone // must be last

)


var engineNames []string

var engineNameToValue map[string]Engine


func init() {

    engineNames = []string{"Unknown", "Docker"}

    engineNameToValue = make(map[string]Engine)

    for i, name := range engineNames {

        engineNameToValue[strings.ToLower(name)] = Engine(i)

    }

}


func (e Engine) String() string {

    if e < 0 || int(e) >= len(engineNames) {

        panic(fmt.Errorf("Invalid engine code: %d", e))

    }

    return engineNames[e]

}


func ParseEngine(text string) (Engine, error) {

    i, ok := engineNameToValue[strings.ToLower(text)]

    if !ok {

        return engineUnknown, fmt.Errorf("Invalid engine name: %s", text)

    }

    return i, nil

}


func (e Engine) MarshalText() ([]byte, error) {

    return []byte(e.String()), nil

}


func (e *Engine) UnmarshalText(text []byte) (err error) {

    name := string(text)

    *e, err = ParseEngine(name)

    return

}

怎么运行的:


func main() {

    j := Job{Engine: EngineDocker}


    fmt.Printf("%#v\n\n", j)

    out, err := yaml.Marshal(j)

    if err != nil {

        panic(err)

    }

    fmt.Printf("YAML: %s\n", string(out))


    var jj Job

    err = yaml.Unmarshal(out, &jj)

    if err != nil {

        panic(err)

    }

    fmt.Printf("%#v\n\n", jj)


    // == JSON ==

    out, err = json.Marshal(j)

    if err != nil {

        panic(err)

    }

    fmt.Printf("JSON: %s\n", string(out))


    var jjs Job

    err = json.Unmarshal(out, &jjs)

    if err != nil {

        panic(err)

    }

    fmt.Printf("%#v\n\n", jjs)


}

输出


main.Job{Engine:1}


YAML: Engine: Docker


main.Job{Engine:1}


JSON: {"Engine":"Docker"}

main.Job{Engine:1}

看?它无需任何额外工作即可将字符串写入 YAML 和 JSON 并从中读取。


查看完整回答
反对 回复 2023-02-21
  • 1 回答
  • 0 关注
  • 166 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号