欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

go中利用reflect實(shí)現(xiàn)json序列化的示例代碼

 更新時(shí)間:2024年03月26日 08:23:02   作者:uccs  
和Java語(yǔ)言一樣,Go也實(shí)現(xiàn)運(yùn)行時(shí)反射,這為我們提供一種可以在運(yùn)行時(shí)操作任意類型對(duì)象的能力,本文給大家介紹了在go中如何利用reflect實(shí)現(xiàn)json序列化,需要的朋友可以參考下

利用反射實(shí)現(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ù)的作用是返回一個(gè)包含給定值的 reflect.Value 類型的值

拿到值 rv之后 ,使用 rv.Type().Kind() 就能拿到用戶傳入值的底層類型

rv.Type() 拿到的值是 reflect.Type 類型,沒法用來(lái)判斷,所以需要使用 rv.Type().Kind() 拿到 reflect.Kind

判斷 int 類型

int 類型有 intint8、int16int32、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 類型可以簡(jiǎn)單理解為數(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 拿到每一項(xiàng)的內(nèi)容,可以通過 `rv.Index(i).Interface()

然后調(diào)用 jsonMarshal 函數(shù),傳入 slice 中的每一項(xiàng)內(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 類型類似于對(duì)象,返回的類型是對(duì)象的 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ù)

我們先定義一個(gè)結(jié)構(gòu)體

type Person struct {
  Name       string `json:"name"`
  Age        int    `json:"age"`
  isMarraied bool   `json:"is_marraied"`
}

這個(gè)結(jié)構(gòu)體中,有兩個(gè)地方需要注意:

  • 小寫字母開頭的屬性,不需要序列化
  • 按照 json_tag 的值來(lái)序列化

通過 rv.NumField 獲取到結(jié)構(gòu)體中的所有的屬性,然后使用 for 循環(huán)遍歷

通過 rv.Field(i) 獲取到屬性的值,通過 rv.Type().Field(i).Tag.Get("json") 獲取到 json 標(biāo)簽的值

如果屬性名是小寫字母開頭的,不需要序列化,直接跳過,通過 isFieldExported 函數(shù)完成

func isFieldExported(name string) bool {
  r, _ := utf8.DecodeRuneInString(name)
  return unicode.IsUpper(r)
}

然后調(diào)用 jsonMarshal 函數(shù),傳入結(jié)構(gòu)體中的每一項(xiàng)內(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)
  }
}

對(duì)應(yīng)的源碼:to_json

到此這篇關(guān)于go中利用reflect實(shí)現(xiàn)json序列化的示例代碼的文章就介紹到這了,更多相關(guān)go reflect json序列化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • golang下grpc框架的使用編寫示例

    golang下grpc框架的使用編寫示例

    這篇文章主要為大家介紹了golang下grpc框架的使用編寫示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • Golang 空map和未初始化map的注意事項(xiàng)說明

    Golang 空map和未初始化map的注意事項(xiàng)說明

    這篇文章主要介紹了Golang 空map和未初始化map的注意事項(xiàng)說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧
    2021-04-04
  • 詳解Golang中Requests包的使用

    詳解Golang中Requests包的使用

    Go的net/http包雖然功能強(qiáng)大、用途也廣告,但要想正確的使用請(qǐng)求的客戶端是非常繁瑣的,所以本文和大家分享一個(gè)高效的HTTP的請(qǐng)求包c(diǎn)arlmjohnson/requests的使用,需要的小伙伴可以了解一下
    2023-06-06
  • Golang之如何讀取文件內(nèi)容

    Golang之如何讀取文件內(nèi)容

    這篇文章主要介紹了Golang之如何讀取文件內(nèi)容問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • go語(yǔ)言中int和byte轉(zhuǎn)換方式

    go語(yǔ)言中int和byte轉(zhuǎn)換方式

    這篇文章主要介紹了go語(yǔ)言中int和byte轉(zhuǎn)換方式,需要的朋友可以參考下
    2018-11-11
  • GO中?分組聲明與array,?slice,?map函數(shù)

    GO中?分組聲明與array,?slice,?map函數(shù)

    這篇文章主要介紹了GO中?分組聲明與array,slice,map函數(shù),Go語(yǔ)言中,同時(shí)聲明多個(gè)常量、變量,或者導(dǎo)入多個(gè)包時(shí),可采用分組的方式進(jìn)行聲明,下面詳細(xì)介紹需要的小伙伴可以參考一下
    2022-03-03
  • Go?代碼塊作用域變量遮蔽問題解析

    Go?代碼塊作用域變量遮蔽問題解析

    這篇文章主要為大家介紹了Go?代碼塊作用域變量遮蔽問題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Go語(yǔ)言中CGO的使用實(shí)踐

    Go語(yǔ)言中CGO的使用實(shí)踐

    本文主要介紹了Go語(yǔ)言中CGO的使用實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • golang結(jié)構(gòu)體與json格式串實(shí)例代碼

    golang結(jié)構(gòu)體與json格式串實(shí)例代碼

    本文通過實(shí)例代碼給大家介紹了golang結(jié)構(gòu)體與json格式串的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-10-10
  • 詳解Go 1.22 for循環(huán)的兩處重要更新

    詳解Go 1.22 for循環(huán)的兩處重要更新

    這篇文章主要詳細(xì)介紹了Go 1.22 for循環(huán)的兩處重要更新,Go 1.22 版本于 2024 年 2 月 6 日發(fā)布,引入了幾個(gè)重要的特性和改進(jìn),在語(yǔ)言層面上,這個(gè)版本對(duì) for 循環(huán)進(jìn)行了兩處更新,本文將會(huì)對(duì) for 循環(huán)的兩個(gè)更新進(jìn)行介紹,需要的朋友可以參考下
    2024-02-02

最新評(píng)論