看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