想必你已经掌握了反射的相关操作,也能够遍历结构体的字段和方法,现在我们就要进入实战了。

1. 问题

正如标题所指,我们的目标是能将任意类型的结构体序列化成 json. 对应的 golang 的encoding/jsong 包就是 Marshal 函数, C++ 的 jsoncpp 库来说就是 write 或 fastwrite 方法,对应到 JavaScript 就是 JSON.stringify 函数了。

你可以在你的浏览器中打开 console 控制台,输入下面的语句:

var p = {name: 'allen', age: 11};
JSON.stringify(p);

你会看到类似一个结构体或者 map 对象被转成了字符串。是的,我们要在 golang 中完成类似 stringify 这样的函数。如果你还记得 golang 的 encoding/json 包的话,一定记得当时我们还用过 Marshal 这个函数,它可以把任意的类型序列化成一个 json 串。

2. 程序

2.1 主程序

// main.go
package mainimport "fmt"type Person struct {Name    stringage     int32friends []*Person
}func main() {zoro := Person{Name: "zoro",age:  10,}luffy := Person{Name: "luffy",age:  18,friends: []*Person{&zoro,},}allen := Person{Name: "allen",age:  19,friends: []*Person{&luffy,&zoro,},}// 我们的目标是将这个 map 序列化成 json 串persons := map[string]Person{"allen": allen,"luffy": luffy,"zoro":  zoro,}// Parse 就是我们要编写的函数buf, err := Parse(persons)if err != nil {fmt.Printf("%v\n", err)return}fmt.Printf("%v\n", string(buf))
}

2.2 Parse 函数

// parse.go
package mainimport ("bytes""fmt""reflect"
)func Parse(v interface{}) ([]byte, error) {var buf bytes.Bufferif err := parse(&buf, reflect.ValueOf(v)); err != nil {return nil, err}return buf.Bytes(), nil
}// parse 是一个内置的递归函数
func parse(buf *bytes.Buffer, v reflect.Value) error {// 取到变量的类型的类别switch v.Kind() {case reflect.Invalid:buf.WriteString("null")case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:fmt.Fprintf(buf, "%d", v.Int())case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:fmt.Fprintf(buf, "%d", v.Uint())case reflect.String:fmt.Fprintf(buf, `"%s"`, v.String())case reflect.Ptr:// 如果是指针,则解引用后继续解析return parse(buf, v.Elem())case reflect.Slice, reflect.Array:buf.WriteByte('[')for i := 0; i < v.Len(); i++ {if i > 0 {buf.WriteString(", ")}if err := parse(buf, v.Index(i)); err != nil {return err}}buf.WriteByte(']')case reflect.Struct:buf.WriteByte('{')for i := 0; i < v.NumField(); i++ {if i > 0 {buf.WriteString(", ")}// key 为结构体字段名称fmt.Fprintf(buf, `"%s":`, v.Type().Field(i).Name)// value 需要递归解析,因为 value 也需要序列化成 json 串if err := parse(buf, v.Field(i)); err != nil {return err}}buf.WriteByte('}')case reflect.Map:buf.WriteByte('{')for i, key := range v.MapKeys() {if i > 0 {buf.WriteString(", ")}fmt.Fprintf(buf, `"%s":`, key)if err := parse(buf, v.MapIndex(key)); err != nil {return err}}buf.WriteByte('}')default:return fmt.Errorf("unsupported type: %s", v.Type())}return nil
}

2.3 编译和运行

> go run main.go parse.go

3. 关于 Elem 方法

func (v Value) Elem() Value

Elem returns the value that the interface v contains or that the pointer v points to. It panics if v’s Kind is not Interface or Ptr. It returns the zero Value if v is nil.

Elem 方法会返回接口 v 或者指针 v 所指向的值(其实就是解引用)。如果 v 的类型不是 Interface 或 Ptr,调用此方法程序就 panic 了(挂了)。如果 v 是 nil 指针,返回对应类型的零值(零值不是数字 0)。

下一篇我们还会遇到这个 Elem 方法。

4. 总结

  • 熟练掌握反射解析现实问题

083-反射(序列化 json)相关推荐

  1. Jackson通过反射将Json转化为java对象

    Jackson的功能比较强大,我们这里主要使用Data Binding的方式,来看看如何使用反射将json转化为java bean,先加入如下依赖: Jackson 的核心模块由三部分组成. jack ...

  2. java json太长_修复Long类型太长,而Java序列化JSON丢失精度问题的方法

    Java序列化JSON时long型数值,会出现精度丢失的问题. 原因: java中得long能表示的范围比js中number大,也就意味着部分数值在js中存不下(变成不准确的值). 解决办法一: 使用 ...

  3. 常用模块(数据序列化 json、pickle、shelve)

    本节内容 前言 json模块 pickle模块 shelve模块 总结 一.前言 1. 现实需求 每种编程语言都有各自的数据类型,其中面向对象的编程语言还允许开发者自定义数据类型(如:自定义类),Py ...

  4. json反射java对象_Jackson通过反射将Json转化为java对象

    Jackson的功能比较强大,我们这里主要使用Data Binding的方式,来看看如何使用反射将json转化为java bean,先加入如下依赖: Jackson 的核心模块由三部分组成. jack ...

  5. biginteger和long精度_修复Long类型太长,而Java序列化JSON丢失精度问题的方法

    造成原因:JS内置有32位整数,而number类型的安全整数是53位.如果超过53位,则精度会丢失.正如现在后台传来一个64位的Long型整数,因此超过了53位,所以后台返回的值和前台获取的值会不一样 ...

  6. 使用go反射校验json是否符合格式

    使用go反射校验json是否符合格式 背景 工作中碰到需要对sbom格式进行校验的情况,sbom官方库没有提供对应的函数操作,所以需要自己根据官方提供的结构体解析对应的json文件,json库提供的反 ...

  7. 计算机程序的思维逻辑 (63) - 实用序列化: JSON/XML/MessagePack

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>(马俊昌著),由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买:京东自营链接 ...

  8. FastJson序列化Json自定义返回字段,普通类从spring容器中获取bean

    前言: 数据库的字段比如:price:1 ,返回需要price:1元. 这时两种途径修改: ① 比如sql中修改或者是在实体类转json前遍历修改. ②返回json,序列化时候修改.用到的是fastj ...

  9. android 序列化 json,android 读取json 为什么不直接反序列化

    我们平时写的bean类,这个是指定规则的序列化对象,虚拟机认得,你说用json反序列化获取对象,这个规则是后台定的,虚拟机如何认得? 而且你说的,很多人一直遍历json字符串,然后一个字段一个字段的封 ...

  10. MongoDB SpringBoot ObjectId序列化json为String

    mongodb的ObjectId默认序列化为bean对象,如果需要转换为json字符对象,配置如下 @Configuration public class JacksonConfig implemen ...

最新文章

  1. django_models_关系一对多
  2. 使用memcache的session入库
  3. Cassandra 常见错误索引
  4. Java之构造器和构造方法的使用和意义
  5. bugku你必须让他停下
  6. 推荐一个算法/数据结构 可视化(Data structure Visualization) 网站
  7. [SQLite]使用记录
  8. 及时沟通的重要性_沟通与代码同样重要
  9. 微课|中学生可以这样学Python(例11.3):tkinter通信录管理系统2
  10. 腾讯地图api修改信息窗口样式_ThingJS通过地图的信息窗口展示常见数据
  11. JAVA day05 构造方法,this关键字,方法的重载,引用类型数组
  12. 九州云黄舒泉当选StarlingX 首届TSC
  13. 通过SQL语句删除重复记录
  14. 四款主流同步软件介绍
  15. RPG游戏-NPC系统
  16. matlab的金融分析工具,金融分析利器之 MATLAB空间计量工具箱
  17. ios10下的通知更新
  18. 从全球制造业的迁移史,看中国制造业未来会怎么走?
  19. 英文版的pdf文件怎么翻译成中文-免费的自动翻译器
  20. 我的战地日记:42期学员闫要峰

热门文章

  1. 非常不错的AI聊天互动平台 AI EDU
  2. 赢过大部分人,掏心窝的12条建议
  3. 中国农业大学2022年法学硕士研究生拟录取名单
  4. UG NX 12 通过点构造面
  5. D3 vs G2 vs Echarts以及其他可视化图表
  6. linux 前后台任务命令 bg、fg、ctrl+z、ctrl+d和ctrl+c 使用
  7. cl.exe link.exe用法详解
  8. 解析人脸识别中cosface和arcface(insightface)的损失函数以及源码
  9. OpenLayers 学习笔记(一)
  10. 一个页面不能同时存在两个 window.onload()的解决方案