go语言实现序列化结构体的私有变量

62 阅读1分钟

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