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

如何取消封送一个JSON字段,该字段要么是结构体,要么是结构体数组?

如何取消封送一个JSON字段,该字段要么是结构体,要么是结构体数组?

Go
慕沐林林 2022-09-19 17:24:58
用例我有一个API,在其中我将用户输入作为对象或对象数组接收。喜欢这个:不带数组的 JSON{  "sign": {    "page_no": 1,    "x_coord": 100,    "y_coord": 300  }}带有数组的 JSON{  "sign": [    {      "page_no": 1,      "x_coord": 100,      "y_coord": 300    },    {      "page_no": 2,      "x_coord": 200,      "y_coord": 400    }  ]}结构到昂马沙尔到type Document struct {  Sign []Sign `json:"sign"` // or just Sign}type Sign struct {  PageNo int `json:"page_no"`  XCoord int `json:"x_coord"`  YCoord int `json:"y_coord"`}由于遗留的原因,我无法将上的字段作为所有用户输入的数组,因此它需要既是数组又只是。SignDocumentSignSign如何取消封送,以便它可以处理下面的两个JSON请求?我知道那件事。。。我们可以使用而不是结构,但这会导致太多的关键断言,当我使用结构时,您不必这样做,因为我可以为它们利用零值。map[string]interface{}另外,这个答案在堆栈溢出似乎没问题,但我想知道有没有更好的方法来做到这一点?
查看完整描述

3 回答

?
偶然的你

TA贡献1841条经验 获得超3个赞

使用自定义 json 取消封口方法创建切片类型。然后,在该解编中,您可以检测您拥有的输入类型,并相应地执行操作。此方法在我的视频 Go 中的高级 JSON 处理中进一步详细说明。

type Signs []Sign


func (s *Signs) UnmarshalJSON(d []byte) error {

    if d[0] == '{' {

        // We know it's a single object

        var v Sign

        err := json.Unmarshal(d, &v)

        *s = Signs{v}

        return err

    }

    // Otherwise it's an array

    var v []Sign

    err := json.Unmarshal(d, &v)

    *s = Signs(v)

    return err

}


查看完整回答
反对 回复 2022-09-19
?
慕虎7371278

TA贡献1802条经验 获得超4个赞

可以通过实现自定义取消封口程序,在完全没有(或类型断言)的情况下执行此操作。我会通过窥视JSON内部并检查它是否以方括号或大括号开头来实现取消元帅...跳过空格。interface{}

请参阅 json。文档中的解封接口

type Document struct {

    Sign SignList

}


type SignList []Sign


func (l *SignList) UnmarshalJSON(d []byte) error {

    for _, b := range d {

        switch b {

        // These are the only valid whitespace in a JSON object.

        case ' ', '\n', '\r', '\t':

        case '[':

            return json.Unmarshal(d, (*[]Sign)(l))

        case '{':

            var obj Sign

            if err := json.Unmarshal(d, &obj); err != nil {

                return err

            }

            *l = []Sign{obj}

            return nil

        default:

            return errors.New("sign must be object or list")

        }

    }

    return errors.New("sign must be object or list")

}

这似乎有点笨拙。哦,好吧。除了编码/json 之外,还有用于 Go 的替代 JSON 取消编组库。如果您愿意,请尝试使用替代的 JSON 库。此代码仅适用于编码/json。


下面介绍如何测试此代码是否正常工作:


package main


import (

    "fmt"

    "encoding/json"

    "errors"

)


type Sign struct {

    X int

}


func main() {

    cases := []string {

        `{"Sign": {"X": 1}}`,

        `{"Sign": [{"X": 1}, {"X": 2}]}`,

    }

    for _, c := range cases {

        var doc Document

        if err := json.Unmarshal([]byte(c), &doc); err != nil {

            fmt.Println("Error:", err)

            continue

        }

        fmt.Printf("Document: %+v\n", &doc)

    }

}

打印如下:


Document: &{Sign:[{X:1}]}

Document: &{Sign:[{X:1} {X:2}]}


查看完整回答
反对 回复 2022-09-19
?
繁星淼淼

TA贡献1775条经验 获得超11个赞

实现一个可以验证数据的类型进行测试,并将其用作检查。


例如:


package main


type SignTest struct {

    Sign map[string]interface{} `json:"sign"`

}


func main() {

    s := `{

  "sign": [

    {

      "page_no": 1,

      "x_coord": 100,

      "y_coord": 300

    },

    {

      "page_no": 2,

      "x_coord": 200,

      "y_coord": 400

    }

  ]

}`


    err := json.Unmarshal([]byte(s), &SignTest{})


    if err != nil {

        fmt.Println("Document Type")

    } else {

        fmt.Println("Sign Type")

    }

}

打印 ,而Document Type


package main



type SignTest struct {

    Sign map[string]interface{} `json:"sign"`

}


func main() {

    s := `{

  "sign": {

    "page_no": 1,

    "x_coord": 100,

    "y_coord": 300

  }

}`


    err := json.Unmarshal([]byte(s), &SignTest{})


    if err != nil {

        fmt.Println("Document Type")

    } else {

        fmt.Println("Sign Type")

    }

}

指纹。Sign Type


但是,在取消编组符号以外的对象是否是数组时,这里可能会出错,如果您想要更安全,请检查错误的错误消息,该错误应按预期方式假设为 。Document


查看完整回答
反对 回复 2022-09-19
  • 3 回答
  • 0 关注
  • 102 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信