go中利用reflect實現(xiàn)json序列化的示例代碼
利用反射實現(xiàn)json
序列化
type Person struct { Name string `json:"name"` Age int `json:"age"` IsMarraied bool `json:"is_marraied"` } k := map[int]Person{ 1: {Name: "uccs", Age: 18, IsMarraied: false}, 2: {Name: "uccs", Age: 18, IsMarraied: true}, 3: {Name: "uccs", Age: 18, IsMarraied: true}, } s := &[...]interface{}{ 1, &Person{Name: "uccs", Age: 18, IsMarraied: false}, Person{Name: "uccs", Age: 18, IsMarraied: true}, true, Person{Name: "uccs", Age: 18, IsMarraied: true}, }
reflect.ValueOf()
函數(shù)的作用是返回一個包含給定值的 reflect.Value
類型的值
拿到值 rv
之后 ,使用 rv.Type().Kind()
就能拿到用戶傳入值的底層類型
rv.Type()
拿到的值是 reflect.Type
類型,沒法用來判斷,所以需要使用 rv.Type().Kind()
拿到 reflect.Kind
判斷 int 類型
int
類型有 int
、int8
、int16
、int32
、int64
,返回 fmt.Sprintf("%v", rv.Int())
func JsonMarshal(v interface{}) (string, error) { rv := reflect.ValueOf(v) rt := rv.Type() switch rt.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return fmt.Sprintf("%v", rv.Int()), nil default: return "", fmt.Errorf("unsupported type: %s", rt) } }
判斷 float 類型
float
類型有 float32
和 float64
,返回 fmt.Sprintf("%v", rv.Float())
func JsonMarshal(v interface{}) (string, error) { rv := reflect.ValueOf(v) rt := rv.Type() switch rt.Kind() { case reflect.Float32, reflect.Float64: return fmt.Sprintf("%v", rv.Float()), nil default: return "", fmt.Errorf("unsupported type: %s", rt) } }
判斷 string 類型
string
類型,返回 fmt.Sprintf("%q", rv.String())
func JsonMarshal(v interface{}) (string, error) { rv := reflect.ValueOf(v) rt := rv.Type() switch rt.Kind() { case reflect.String: return fmt.Sprintf("%q", rv.String()), nil default: return "", fmt.Errorf("unsupported type: %s", rt) } }
判斷 bool 類型
bool
類型,返回 fmt.Sprintf("%v", rv.Bool())
func JsonMarshal(v interface{}) (string, error) { rv := reflect.ValueOf(v) rt := rv.Type() switch rt.Kind() { case reflect.Bool: return fmt.Sprintf("%v", rv.Bool()), nil default: return "", fmt.Errorf("unsupported type: %s", rt) } }
判斷 slice 類型
slice
類型可以簡單理解為數(shù)組,返回的類型是數(shù)組的 json
字符串
func JsonMarshal(v interface{}) (string, error) { rv := reflect.ValueOf(v) rt := rv.Type() switch rt.Kind() { case reflect.Slice: return marshalSlice(rv) default: return "", fmt.Errorf("unsupported type: %s", rt) } }
處理 slice
的過程封裝為 marshalSlice
函數(shù)
需要遍歷 slice
拿到每一項的內(nèi)容,可以通過 `rv.Index(i).Interface()
然后調(diào)用 jsonMarshal
函數(shù),傳入 slice
中的每一項內(nèi)容,遞歸處理
最后拼接出數(shù)組格式的 json
字符串,使用 strings.Join(items, ",")
拼接
func marshalSlice(rv reflect.Value) (string, error) { var items []string for i := 0; i < rv.Len(); i++ { value, err := JsonMarshal(rv.Index(i).Interface()) if err != nil { return "", err } items = append(items, value) } return "[" + strings.Join(items, ",") + "]", nil }
判斷 array 類型
處理 array
類型和處理 slice
是一樣的,只需要將 array
轉(zhuǎn)換為 slice
,在反射中可以使用 rv.Slice(0, rv.Len())
func JsonMarshal(v interface{}) (string, error) { rv := reflect.ValueOf(v) rt := rv.Type() switch rt.Kind() { case reflect.Array: return marshalSlice(rv.Slice(0, rv.Len())) default: return "", fmt.Errorf("unsupported type: %s", rt) } }
判斷 struct 類型
struct
類型類似于對象,返回的類型是對象的 json
字符串
func JsonMarshal(v interface{}) (string, error) { rv := reflect.ValueOf(v) rt := rv.Type() switch rt.Kind() { case reflect.Struct: return marshalStruct(rv) default: return "", fmt.Errorf("unsupported type: %s", rt) } }
處理 struct
的過程封裝為 marshalStruct
函數(shù)
我們先定義一個結(jié)構(gòu)體
type Person struct { Name string `json:"name"` Age int `json:"age"` isMarraied bool `json:"is_marraied"` }
這個結(jié)構(gòu)體中,有兩個地方需要注意:
- 小寫字母開頭的屬性,不需要序列化
- 按照
json_tag
的值來序列化
通過 rv.NumField
獲取到結(jié)構(gòu)體中的所有的屬性,然后使用 for
循環(huán)遍歷
通過 rv.Field(i)
獲取到屬性的值,通過 rv.Type().Field(i).Tag.Get("json")
獲取到 json
標簽的值
如果屬性名是小寫字母開頭的,不需要序列化,直接跳過,通過 isFieldExported
函數(shù)完成
func isFieldExported(name string) bool { r, _ := utf8.DecodeRuneInString(name) return unicode.IsUpper(r) }
然后調(diào)用 jsonMarshal
函數(shù),傳入結(jié)構(gòu)體中的每一項內(nèi)容,遞歸處理
最后拼接出數(shù)組格式的 json
字符串,使用 strings.Join(items, ",")
拼接
func marshalStruct(rv reflect.Value) (string, error) { var items []string for i := 0; i < rv.NumField(); i++ { fieldValue := rv.Field(i) jsonTag := rv.Type().Field(i).Tag.Get("json") key := rv.Type().Field(i).Name if !isFieldExported(key) { continue } if jsonTag != "" { key = jsonTag } value, err := JsonMarshal(fieldValue.Interface()) if err != nil { return "", err } items = append(items, fmt.Sprintf("%q:%v", key, value)) } return "{" + strings.Join(items, ",") + "}", nil }
處理 pointer 類型
處理 pointer
類型,需要先判斷 pointer
指向的類型
- 如果是
array
類型,需要將pointer
轉(zhuǎn)換為slice
,然后調(diào)用marshalSlice
函數(shù) - 如果是
struct
類型,直接調(diào)用marshalStruct
func JsonMarshal(v interface{}) (string, error) { rv := reflect.ValueOf(v) rt := rv.Type() switch rt.Kind() { case reflect.Pointer: if rv.Elem().Kind() == reflect.Array { return marshalSlice(rv.Elem().Slice(0, rv.Len())) } if rv.Elem().Kind() == reflect.Struct { return JsonMarshal(rv.Elem().Interface()) } return JsonMarshal(rv.Elem().Interface()) default: return "", fmt.Errorf("unsupported type: %s", rt) } }
對應的源碼:to_json
到此這篇關于go中利用reflect實現(xiàn)json序列化的示例代碼的文章就介紹到這了,更多相關go reflect json序列化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
GO中?分組聲明與array,?slice,?map函數(shù)
這篇文章主要介紹了GO中?分組聲明與array,slice,map函數(shù),Go語言中,同時聲明多個常量、變量,或者導入多個包時,可采用分組的方式進行聲明,下面詳細介紹需要的小伙伴可以參考一下2022-03-03golang結(jié)構(gòu)體與json格式串實例代碼
本文通過實例代碼給大家介紹了golang結(jié)構(gòu)體與json格式串的相關知識,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-10-10