十分鐘教你寫一個 Json 解析庫
json是在開發當中一種常見的數據結構,本身它的協議棧就是很簡潔的,如果有興趣的同學,可以參考RFC4627文檔,本文的最后我會附上這部分的鏈接,方便大家查看。那么在go項目的開發當中,比如最常見的web項目,我們需用到json來傳遞數據,那么必然就會面對將json object,轉換成go中對應的數據結構的需求。無需擔心的是,go提供了encoding/json解析包,我們接下來要做的工作就是在此基礎上做一定封裝,以方便自己使用。同時這個庫也是特別適合新手來練手使用,因為它設計到了go中的map,struct,assert,interface{}...,所以對于加深對go基礎的理解也很有幫助,甚至你還可以寫出更好的呢!
項目地址: https://github.com/liyu4/ljson
開始
定義一個全局對象,data為interface{}類型意味這可以存儲任何類型的數據。
typeJs struct {
datainterface{}
}
工廠模式實例化Js對象,這里我們將需要反序列化的data數據,先轉換成byte數組, 然后將其解析到&f指向的值中,也就是說f是包含了我們反序列化得到的數據。本文接下來的部分就是對這個f的操作。
funcNewJson(datastring) *Js {
j:= new(Js)
varfinterface{}
err:=json.Unmarshal([]byte(data), &f)
if nil !=err{
returnj
}
j.data=f
returnj
}
獲取map,這里我們使用了斷言,判斷interface{}是否是map[string]interface{}類型
// return map in Go
func(j*Js) GetMapData()map[string]interface{} {
ifm,ok:= (j.data).(map[string]interface{});ok{
returnm
}
return nil
}
獲取key對應的value
// Acoording to the key of the returned data information , return js.data
// if you know json is an object
func(j*Js) Get(keystring) *Js {
m:=j.GetMapData()
ifv,ok:=m[key];ok{
j.data=v
returnj
}
j.data= nil
returnj
}
或者value根據下標,這里指的是從slice和map中,你懂的,這里有一個點需要小心一下,就是map返回的順序是不固定的
// GetIndex get []interface or map in Go
func(j*Js) GetIndex(iint) *Js {
num:=i- 1
ifm,ok:= (j.data).([]interface{});ok{
ifnum<=len(m)-1{
v:=m[num]
j.data=v
}else{
j.data= nil
}
returnj
}
{
ifm,ok:= (j.data).(map[string]interface{});ok{
varn= 0
vardata=make(map[string]interface{})
fori,v:=range m{
ifn==num{
switchvv:=v.(type) {
casefloat64:
data[i] =strconv.FormatFloat(vv, 'f', -1, 64)
j.data=data
returnj
case string:
data[i] =vv
j.data=data
returnj
case []interface{}:
j.data=vv
returnj
}
}
n++
}
}
}
j.data= nil
returnj
}
自定義key和下標返回value,注意錯誤的處理
// The data must be []interface{}, According to your custom number to return key adn array data
func(j*Js) GetKey(keystring,iint) (*Js,error) {
num:=i- 1
ifi>len((j.data).([]interface{})) {
return nil,errors.New("index out of range list")
}
ifm,ok:= (j.data).([]interface{});ok{
v:=m[num].(map[string]interface{})
ifh,ok:=v[key];ok{
j.data=h
returnj, nil
}
}
j.data= nil
returnj, nil
}
遞歸map
// According to the custom of the PATH to fing element
// You can use function this to find recursive map
func(j*Js) GetPath(args...string) *Js {
d:=j
fori:=range args{
m:=d.GetMapData()
ifval,ok:=m[args[i]];ok{
d.data=val
} else {
d.data= nil
returnd
}
}
returnd
}
String方法,相信大家也看到了我們的slice和map中的值都是interface{},轉換陳string能方便我們的操作。
// String return string
func(j*Js) String() string {
ifm,ok:=j.data.(string);ok{
returnm
}
ifm,ok:=j.data.(float64);ok{
returnstrconv.FormatFloat(m, 'f', -1, 64)
}
return ""
}
返回key和value數組 []string
func(j*Js) ToArray() (k,d[]string) {
varkey,data[]string
ifm,ok:= (j.data).([]interface{});ok{
for_,value:=range m{
forindex,v:=range value.(map[string]interface{}) {
switchvv:=v.(type) {
casefloat64:
data=append(data,strconv.FormatFloat(vv, 'f', -1, 64))
key=append(key,index)
case string:
data=append(data,vv)
key=append(key,index)
}
}
}
returnkey,data
}
ifm,ok:= (j.data).(map[string]interface{});ok{
forindex,v:=range m{
switchvv:=v.(type) {
casefloat64:
data=append(data,strconv.FormatFloat(vv, 'f', -1, 64))
key=append(key,index)
case string:
data=append(data,vv)
key=append(key,index)
}
}
returnkey,data
}
return nil, nil
}
返回一個[]string
// Array return array
func(j*Js) Array() ([]string,error) {
ifa,ok:= (j.data).([]interface{});ok{
array:=make([]string, 0)
for_,v:=range a{
switchvv:=v.(type) {
casefloat64:
array=append(array,strconv.FormatFloat(vv, 'f', -1, 64))
case string:
array=append(array,vv)
}
}
returnarray, nil
}
return nil,errors.New("type assertion to []interface{} failed")
}
一個漂亮但是沒啥子用的調試函數
//for test
func(j*Js) Type() {
fmt.Println(reflect.TypeOf(j.data))
}
至此我們就完成了一個可以部署在生產環境中的json library,這個項目是小巧和堅實的,希望大家能自己動手寫寫,最好是在下雨的星期天下午。
參考
來自:https://www.zybuluo.com/aliasliyu4/note/601706