简体   繁体   English

当给定的 JSON 值不是 JSON object 时,解组自定义结构

[英]Unmarshal a custom struct when the JSON value given is not a JSON object

I have a custom struct defined that I'm using to Unmarshal an API response into.我定义了一个自定义结构,用于将 API 响应解组到其中。 Sometimes, the API decides to send an empty string ( "" ) when the object is empty or missing.有时,当 object 为空或缺失时,API 决定发送一个空字符串 ( "" )。 I'm unclear how to handle this type mismatch.我不清楚如何处理这种类型不匹配。 I actually have hundreds of these custom structs (nested) and the API will do this for the top-most parent if it is empty.我实际上有数百个这样的自定义结构(嵌套),如果 API 为空,它将为最顶层的父级执行此操作。 If there is some way to do this globally without the need for a custom UnmarshalJSON method, that would be ideal.如果有某种方法可以在不需要自定义UnmarshalJSON方法的情况下全局执行此操作,那将是理想的。 I'm using code generation, so I could add those methods easily.我正在使用代码生成,所以我可以轻松添加这些方法。

When I first attempted to write my own custom UnmarshalJSON , I ended up in a loop:当我第一次尝试编写自己的自定义UnmarshalJSON时,我最终陷入了一个循环:

func (e MyStruct) UnmarshalJSON(b []byte) error {
    t := MyStruct{}
    if string(b) == `""` {e = t} else {
        if err := json.Unmarshal(b, e); err != nil {
            return fmt.Errorf("failed to parse nested structure: %v", err)
        }
    }
    return nil
}

I understand why I ended up in the loop, but I have a feeling there is a better solution I'm missing.我理解为什么我最终陷入了循环,但我觉得我缺少更好的解决方案。

I've created an example in the Go Playground.我在 Go Playground 中创建了一个示例。

https://play.golang.org/p/DrrFhA3TzPv https://play.golang.org/p/DrrFhA3TzPv

My current, generated code is here if you're looking for more context: https://github.com/mbrancato/edgeos/blob/a8af9143aa82ddece27089bf2f543f473c97d2db/sdk/config.go如果您正在寻找更多上下文,我当前生成的代码在这里: https://github.com/mbrancato/edgeos/blob/a8af9143aa82ddece27089bf2f543f473c97d2db/sdk/config.Z34D1F91FB2A7514B8A676A8

Use the following code to unmarshal the value.使用以下代码解组该值。

var emptyString = []byte(`""`)

func (e *MyStruct) UnmarshalJSON(b []byte) error {
    if bytes.Equal(b, emptyString) {
        *e = MyStruct{}
        return nil
    }
    type t MyStruct
    if err := json.Unmarshal(b, (*t)(e)); err != nil {
        return fmt.Errorf("failed to parse nested structure: %w", err)
    }
    return nil
}

Notes:笔记:

  • UnmarshalJSON must be on pointer receiver. UnmarshalJSON必须在指针接收器上。
  • Avoid recursion by declaring new type t with same underlying type as MyStruct .通过声明与MyStruct具有相同基础类型的新类型t来避免递归。 Unmarshal to a value of type t .解组为t类型的值。
  • Compare bytes instead of string to avoid allocations.比较字节而不是字符串以避免分配。
  • To allow use of errors.As in the caller, use %w as the formatting verb for the error.允许使用错误。在调用者中,使用 %w 作为错误的格式化动词。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM