首页>>后端>>Golang->记录Golang关于JSON 处理遇到的坑(避坑指南)

记录Golang关于JSON 处理遇到的坑(避坑指南)

时间:2023-11-29 本站 点击:0

看JSON处理代码

import("encoding/json""errors""fmt""reflect""strings""testing"jsoniter"github.com/json-iterator/go")//json化funcJsonMarshal(vinterface{})string{varfasterJson=jsoniter.ConfigCompatibleWithStandardLibraryb,err:=fasterJson.Marshal(v)iferr!=nil{logs.Error("JsonMarshalfailedforv:%+v",v)return`{"err_msg":"notjsonformat"}`}returnstring(b)}//反json化,jsonStr是json化的字符串,v传空的结构体funcJsonUnmarshal(jsonStrstring,vinterface{})error{varfasterJson=jsoniter.ConfigCompatibleWithStandardLibrarybyteValue:=[]byte(jsonStr)err:=fasterJson.Unmarshal(byteValue,v)iferr!=nil{logs.Error("JsonUnmarshalfailedforv:%+v,err=%s",v,err.Error())returnerrors.New("JsonUnmarshalfailedforv:%+v")}returnnil}

字符串为空的处理

json 包在对空字符串的处理,非常容易出错

"" 与”{}"

typeUserstruct{NamestringFansCountint64}funcTestJsonMashal3(t*testing.T){str:="{}"varuserUsererr:=JsonUnmarshal(str,&user)fmt.Println(err,user)str1:=""varuser1Usererr1:=JsonUnmarshal(str1,&user)fmt.Println(err1,user1)}

执行结果:

===RUNTestJsonMashal3<nil>{0}JsonUnmarshalfailedforv:%+v{0}---PASS:TestJsonMashal3(0.00s)PASS

可以看到 在处理 空字符串“” 时 程序抛出异常 JsonUnmarshal failed for v: %+v { 0}但是如果是 空 json "{}" 发现是可以处理的, 返回的结果是 { 0}

字段为空的处理

typePersonstruct{NamestringAgeint64Birthtime.TimeChildren[]Person}funcTestJsonMashalEmpty(t*testing.T){person:=Person{}jsonBytes:=JsonMarshal(person)fmt.Println(string(jsonBytes))//{"Name":"","Age":0,"Birth":"0001-01-01T00:00:00Z","Children":null}}

执行结果

===RUNTestJsonMashal4{"Name":"","Age":0,"Birth":"0001-01-01T00:00:00Z","Children":null}---PASS:TestJsonMashal4(0.00s)PASS

发现没,当是 struct 中 的字段没有值时, 使用json.Marshal 方法并不会忽略这些字段,而是输出了他们的默认空值, 这个往往和我们的预期不一致。int 和 float 类型零值是 0,string 类型零值是 "",对象类型零值是 nil。

有没有办法忽略这些空字段?有, 加一个 omitempty tag 就可以了。

typePersonAllowEmptystruct{Namestring`json:",omitempty"`Ageint64`json:",omitempty"`Birthtime.Time`json:",omitempty"`Children[]PersonAllowEmpty`json:",omitempty"`}funcTestMarshalEmpty2(t*testing.T){person:=PersonAllowEmpty{}jsonBytes:=JsonMarshal(person)fmt.Println(string(jsonBytes))//{"Birth":"0001-01-01T00:00:00Z"}}

运行结果

===RUNTestMarshalEmpty2{"Birth":"0001-01-01T00:00:00Z"}---PASS:TestMarshalEmpty2(0.00s)PASS

字段在任何情况下都被 json 忽略要怎么做?

typePersonstruct{Namestring`json:"-"`Ageint64`json:"-"`Birthtime.Time`json:"-"`Children[]string`json:"-"`}funcmain(){birth,_:=time.Parse(time.RFC3339,"1988-12-02T15:04:27+08:00")person:=Person{Name:"WangWu",Age:30,Birth:birth,Children:[]string{},}jsonBytes,_:=json.Marshal(person)fmt.Println(string(jsonBytes))//{}}

使用 json:"-" 标签即可忽略所有字段, 输出的结果就是 {} 空 json,不是空字符串。

JSON 处理中精度丢失的问题

反序列化时明确指定了明确的结构体和类型

typeUserstruct{NamestringFansCountint64}//如果反序列化的时候指定明确的结构体和变量类型funcTestJsonUnmarshal(t*testing.T){constjsonStream=`{"name":"ethancai","fansCount":9223372036854775807}`varuserUser//类型为Usererr:=JsonUnmarshal(jsonStream,&user)iferr!=nil{fmt.Println("error:",err)}fmt.Printf("%+v\n",user)}

运行结果:

===RUNTestJsonUnmarshal{Name:ethancaiFansCount:9223372036854775807}---PASS:TestJsonUnmarshal(0.00s)PASS

反序列化时不指定结构体类型或者变量,JSON 数据类型,默认是 float64

typeUserstruct{NamestringFansCountint64}funcTestJsonMashal3(t*testing.T){str:="{}"varuserUsererr:=JsonUnmarshal(str,&user)fmt.Println(err,user)str1:=""varuser1Usererr1:=JsonUnmarshal(str1,&user)fmt.Println(err1,user1)}0

运行结果:

typeUserstruct{NamestringFansCountint64}funcTestJsonMashal3(t*testing.T){str:="{}"varuserUsererr:=JsonUnmarshal(str,&user)fmt.Println(err,user)str1:=""varuser1Usererr1:=JsonUnmarshal(str1,&user)fmt.Println(err1,user1)}1

可以看到,如果数据精度比较高的时候,反序列化成 float64 类型的数值时存在精度丢失的问题。

JSON 时间格式日期处理问题

typeUserstruct{NamestringFansCountint64}funcTestJsonMashal3(t*testing.T){str:="{}"varuserUsererr:=JsonUnmarshal(str,&user)fmt.Println(err,user)str1:=""varuser1Usererr1:=JsonUnmarshal(str1,&user)fmt.Println(err1,user1)}2

运行结果

typeUserstruct{NamestringFansCountint64}funcTestJsonMashal3(t*testing.T){str:="{}"varuserUsererr:=JsonUnmarshal(str,&user)fmt.Println(err,user)str1:=""varuser1Usererr1:=JsonUnmarshal(str1,&user)fmt.Println(err1,user1)}3

JSON的规范中并没有日期类型,不同语言的library对日期序列化的处理也不完全一致, 要特别注意。

结构体字母小写问题

如果机构题字段的首字母是小写, 解析 json 时会失败

typeUserstruct{NamestringFansCountint64}funcTestJsonMashal3(t*testing.T){str:="{}"varuserUsererr:=JsonUnmarshal(str,&user)fmt.Println(err,user)str1:=""varuser1Usererr1:=JsonUnmarshal(str1,&user)fmt.Println(err1,user1)}4

运行结果

typeUserstruct{NamestringFansCountint64}funcTestJsonMashal3(t*testing.T){str:="{}"varuserUsererr:=JsonUnmarshal(str,&user)fmt.Println(err,user)str1:=""varuser1Usererr1:=JsonUnmarshal(str1,&user)fmt.Println(err1,user1)}5

需要修改首字母为大写

typeUserstruct{NamestringFansCountint64}funcTestJsonMashal3(t*testing.T){str:="{}"varuserUsererr:=JsonUnmarshal(str,&user)fmt.Println(err,user)str1:=""varuser1Usererr1:=JsonUnmarshal(str1,&user)fmt.Println(err1,user1)}6

运行结果

typeUserstruct{NamestringFansCountint64}funcTestJsonMashal3(t*testing.T){str:="{}"varuserUsererr:=JsonUnmarshal(str,&user)fmt.Println(err,user)str1:=""varuser1Usererr1:=JsonUnmarshal(str1,&user)fmt.Println(err1,user1)}7


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Golang/220.html