当前位置: 代码网 > it编程>前端脚本>Golang > go中利用reflect实现json序列化的示例代码

go中利用reflect实现json序列化的示例代码

2024年05月15日 Golang 我要评论
利用反射实现json序列化type person struct { name string `json:"name"` age int `json:"age"`

利用反射实现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() 函数的作用是返回一个包含给定值的 reflect.value 类型的值

拿到值 rv之后 ,使用 rv.type().kind() 就能拿到用户传入值的底层类型

rv.type() 拿到的值是 reflect.type 类型,没法用来判断,所以需要使用 rv.type().kind() 拿到 reflect.kind

判断 int 类型

int 类型有 intint8int16int32int64,返回 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 类型可以简单理解为数组,返回的类型是数组的 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 函数

需要遍历 slice 拿到每一项的内容,可以通过 `rv.index(i).interface()

然后调用 jsonmarshal 函数,传入 slice 中的每一项内容,递归处理

最后拼接出数组格式的 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 转换为 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 函数

我们先定义一个结构体

type person struct {
  name       string `json:"name"`
  age        int    `json:"age"`
  ismarraied bool   `json:"is_marraied"`
}

这个结构体中,有两个地方需要注意:

  • 小写字母开头的属性,不需要序列化
  • 按照 json_tag 的值来序列化

通过 rv.numfield 获取到结构体中的所有的属性,然后使用 for 循环遍历

通过 rv.field(i) 获取到属性的值,通过 rv.type().field(i).tag.get("json") 获取到 json 标签的值

如果属性名是小写字母开头的,不需要序列化,直接跳过,通过 isfieldexported 函数完成

func isfieldexported(name string) bool {
  r, _ := utf8.decoderuneinstring(name)
  return unicode.isupper(r)
}

然后调用 jsonmarshal 函数,传入结构体中的每一项内容,递归处理

最后拼接出数组格式的 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 转换为 slice,然后调用 marshalslice 函数
  • 如果是 struct 类型,直接调用 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实现json序列化的示例代码的文章就介绍到这了,更多相关go reflect json序列化内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com