最近開發(fā)過程遇到一個go序列化的問題,
前端要求數(shù)據(jù)返回
{
"user":"zhangsan",
"role":[
{"name":"管理員"},{"name":"觀察者"}
]
}
go中的數(shù)據(jù)結(jié)構(gòu)是這樣的
type Role struct{
Name string `json:"name"`
}
type Info {
User string `json:"user"`
Role []Role `json:"role"`
}
data,_:=json.Marshal(&info{User:"zhangsan"})
fmt.Println(string(data))
如果info.Role沒有數(shù)據(jù)時宝泵,因為go的json標(biāo)準(zhǔn)庫會將空切片好啰、空指針返回null,實際返回給前端的數(shù)據(jù)是這樣的
{
"user":"zhangsan",
"role":null
}
這個數(shù)據(jù)前端拿到后判斷role的長度時就會出錯儿奶,一般的做法是初始化切片Role
type Role struct{
Name string `json:"name"`
}
type Info {
User string `json:"user"`
Role []Role `json:"role"`
}
data:=json.Marshal(&info{User:"zhangsan",Role:[]Role{}})
fmt.Println(string(data))
這樣就可以按照協(xié)定的結(jié)構(gòu)返回數(shù)據(jù)
{
"user":"zhangsan",
"role":[]
}
但是我們存在大量這樣的代碼框往,如果要都初始化一次,那簡直是喪心病狂??闯捎,就像下面這樣
type Info {
User string `json:"user"`
Role []Role
Cols1 []string
Cols2 []string
Cols3 []string
Cols4 []string
Cols5 []string
Cols6 []string
...//不知道還有n多
}
網(wǎng)上找了一大圈也沒找到有處理這種情況的辦法椰弊,還是自己動手寫了個簡單的處理器
package binding
import (
"reflect"
"strconv"
"strings"
)
type marshal struct {
}
//json反序列化
func Marshal(obj interface{}) string {
v := reflect.ValueOf(obj)
return new(marshal).parse(v)
}
//處理開始
func (this *marshal) parse(v reflect.Value) string {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.FormatInt(v.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return strconv.FormatUint(v.Uint(), 10)
case reflect.Float32, reflect.Float64:
return strconv.FormatFloat(v.Float(), 'f', -1, 64)
case reflect.String:
return `"` + v.String() + `"`
case reflect.Bool:
return strconv.FormatBool(v.Bool())
case reflect.Struct:
return this.parseStruct(v, v.Type())
case reflect.Map:
return this.parseMap(v, v.Type())
case reflect.Slice:
return this.parseSlice(v, v.Type())
case reflect.Interface:
return this.parse(reflect.ValueOf(v.Interface()))
}
return "null"
}
//處理結(jié)構(gòu)體
func (this *marshal) parseStruct(v reflect.Value, t reflect.Type) string {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
var str = make([]string, t.NumField())
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := v.Field(i)
fieldName := field.Name
tag := field.Tag.Get("json")
if tag != "" {
f := strings.Split(tag, ",")
fieldName = f[0]
}
if fieldName == "-" {
continue
}
str[i]= `"`+fieldName+`":`+this.parse(value)
}
return "{" + strings.Join(str, ",") + "}"
}
//處理切片
func (this *marshal) parseSlice(v reflect.Value, t reflect.Type) string {
var str = make([]string, v.Len())
for i := 0; i < v.Len(); i++ {
str [i]= this.parse(v.Index(i))
}
return `[` + strings.Join(str, ",") + "]"
}
//處理map
func (this *marshal) parseMap(v reflect.Value, t reflect.Type) string {
var str = make([]string, v.Len())
m := v.MapRange()
var i int
for m.Next() {
str[i]= `"`+m.Key().String()+`":`+this.parse(m.Value())
i++
}
return "{" + strings.Join(str, ",") + "}"
}
使用方法
type Role struct {
Name string `json:"name"`
}
type Info struct {
Name string `json:"name"`
Role []Role `json:"role"`
}
s := Marshal(Info{Name: "zhangsan"})
fmt.Println(s)
輸出結(jié)果
{"name":"zhangsan","role":[]}
好用是好用,但是性能比標(biāo)準(zhǔn)庫差了5倍瓤鼻,一般情況下也足夠了??