dongwei1234 2019-05-27 10:29
浏览 155
已采纳

JSON解组中缺失字段和空字段之间的区别

So I have this struct in Go:

type Car struct {
    Name  string `json:"name"`
    Speed int    `json:"speed"`
}

And I have two JSON samples that I unmarshal:

str := `{"name": "", "speed": 0}`
strTwo := `{}`

I do the unmarshaling in this way:

car := Car{}
_ = json.Unmarshal([]byte(str), &car)

carTwo := Car{}
_ = json.Unmarshal([]byte(strTwo), &carTwo)

Now because of the way Go deals with default value types, when I try to print the structure, I get the same result:

car - { 0}
carTwo - { 0}

So I can't see the difference between a missing value in JSON and when a default value is passed. How can I solve this problem?

One way is to use pointers in struct:

type Car struct {
    Name  *string `json:"name"`
    Speed *int    `json:"speed"`
}

But I get a very ugly code when using this values, I have to do pointer dereferencing everywhere

  • 写回答

1条回答 默认 最新

  • douxian0008 2019-05-27 10:43
    关注

    Go's primitive data types are not suitable to handle the "all valid values" and an additional "is present" information.

    If you do need this, one way is to use pointers, where the nil pointer value corresponds to the "missing" state.

    If it is uncomfortable to work with pointers afterwards, do a "post processing": convert your structs with pointer fields to a struct value with non-pointer fields, so you can work with that later on.

    You may do this "manually", or write a custom unmarshaler to make this happen automatically.

    Here's an example how to do it:

    type PCar struct {
        Name  *string `json:"name"`
        Speed *int    `json:"speed"`
    }
    
    type Car struct {
        Name  string `json:"-"`
        Speed int    `json:"-"`
        PCar
    }
    
    func (c *Car) UnmarshalJSON(data []byte) error {
        if err := json.Unmarshal(data, &c.PCar); err != nil {
            return err
        }
    
        if c.PCar.Name != nil {
            c.Name = *c.PCar.Name
        }
        if c.PCar.Speed != nil {
            c.Speed = *c.PCar.Speed
        }
        return nil
    }
    

    Example using it:

    sources := []string{
        `{"name": "", "speed": 0}`,
        `{}`,
        `{"name": "Bob", "speed": 21}`,
    }
    
    for i, src := range sources {
        var c Car
        if err := json.Unmarshal([]byte(src), &c); err != nil {
            panic(err)
        }
        fmt.Println("car", i, c)
    }
    

    Output (try it on the Go Playground):

    car 0 { 0 {0x40c200 0x4140ac}}
    car 1 { 0 {<nil> <nil>}}
    car 2 {Bob 21 {0x40c218 0x41410c}}
    

    As you can see, car 1 contains 2 non-nil pointers, because the respective fields were present in the input JSON, while car 2 contains 2 nil pointers, because those fields were missing in its input. You may use Car.Name and Car.Speed fields as non-pointers (because they are not pointers). To tell if they were present in the input, you may check the corresponding pointers Car.PCar.Name and Car.PCar.Speed if they are nil.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 C#调用python代码(python带有库)
  • ¥15 矩阵加法的规则是两个矩阵中对应位置的数的绝对值进行加和
  • ¥15 活动选择题。最多可以参加几个项目?
  • ¥15 飞机曲面部件如机翼,壁板等具体的孔位模型
  • ¥15 vs2019中数据导出问题
  • ¥20 云服务Linux系统TCP-MSS值修改?
  • ¥20 关于#单片机#的问题:项目:使用模拟iic与ov2640通讯环境:F407问题:读取的ID号总是0xff,自己调了调发现在读从机数据时,SDA线上并未有信号变化(语言-c语言)
  • ¥20 怎么在stm32门禁成品上增加查询记录功能
  • ¥15 Source insight编写代码后使用CCS5.2版本import之后,代码跳到注释行里面
  • ¥50 NT4.0系统 STOP:0X0000007B