go标准库的json.Marshal是无法序列化结构体的私有变量的,要想实现这个需求,需要用到reflect。大体的思路是,将struct转化成map[string]interface{},然后再调用json,序列化成字符串。实现方式如下:
package json_format
import (
"encoding/json"
"fmt"
"reflect"
)
// FormatStructToJson 格式化json,可以处理私有变量
func FormatStructToJson(v interface{}) string {
bs, _ := json.Marshal(result)
return string(bs)
}
func serialize(v reflect.Value) interface{} {
if !v.IsValid() {
return nil
}
if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
if v.IsNil() {
return nil
}
return serialize(v.Elem())
}
switch v.Kind() {
case reflect.Bool:
return v.Bool()
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
return v.Int()
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return v.Uint()
case reflect.Float32, reflect.Float64:
return v.Float()
case reflect.String:
return v.String()
case reflect.Slice:
if v.IsNil() {
return nil
}
fallthrough
case reflect.Array:
arr := make([]interface{}, 0, v.Len())
for i := 0; i < v.Len(); i++ {
arr = append(arr, serialize(v.Index(i)))
}
return arr
case reflect.Map:
if v.IsNil() {
return nil
}
m := make(map[string]interface{})
keys := v.MapKeys()
for _, key := range keys {
value := v.MapIndex(key)
m[fmt.Sprintf("%v", key)] = serialize(value)
}
return m
case reflect.Struct:
m := make(map[string]interface{})
vt := v.Type()
numFields := v.NumField()
for i := 0; i < numFields; i++ {
m[vt.Field(i).Name] = serialize(v.Field(i))
}
return m
default:
return v.String()
}
}
我们具体看下serialize函数的实现细节。serialize函数将任意数据结构转化成interface{}.输入的数据大致分为以下几种:
- 基础数据类型: 直接还原
case reflect.Bool:
return v.Bool()
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
return v.Int()
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return v.Uint()
case reflect.Float32, reflect.Float64:
return v.Float()
case reflect.String:
return v.String()
- slice && array: 遍历每个元素,递归调用serialize函数
case reflect.Slice:
if v.IsNil() {
return nil
}
fallthrough
case reflect.Array:
arr := make([]interface{}, 0, v.Len())
for i := 0; i < v.Len(); i++ {
arr = append(arr, serialize(v.Index(i)))
}
return arr
- map: 遍历key-value对,key转化成string,递归转化value
case reflect.Map:
if v.IsNil() {
return nil
}
m := make(map[string]interface{})
keys := v.MapKeys()
for _, key := range keys {
value := v.MapIndex(key)
m[fmt.Sprintf("%v", key)] = serialize(value)
}
return m
- strcut: 遍历每个field,将field name作为key,递归转化value
case reflect.Struct:
m := make(map[string]interface{})
vt := v.Type()
numFields := v.NumField()
for i := 0; i < numFields; i++ {
m[vt.Field(i).Name] = serialize(v.Field(i))
}
return m