最近开发过程遇到一个go序列化的问题,
前端要求数据返回
{
"user":"zhangsan",
"role":[
{"name":"管理员"},{"name":"观察者"}
]
}
go中的数据结构是这样的
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没有数据时,因为go的json标准库会将空切片、空指针返回null,实际返回给前端的数据是这样的
{
"user":"zhangsan",
"role":null
}
这个数据前端拿到后判断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))
这样就可以按照协定的结构返回数据
{
"user":"zhangsan",
"role":[]
}
但是我们存在大量这样的代码,如果要都初始化一次,那简直是丧心病狂????,就像下面这样
type Info {
User string `json:"user"`
Role []Role
Cols1 []string
Cols2 []string
Cols3 []string
Cols4 []string
Cols5 []string
Cols6 []string
...//不知道还有n多
}
网上找了一大圈也没找到有处理这种情况的办法,还是自己动手写了个简单的处理器
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"
}
//处理结构体
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)
输出结果
{"name":"zhangsan","role":[]}
好用是好用,但是性能比标准库差了5倍,一般情况下也足够了????
有疑问加站长微信联系(非本文作者)