我们不同编程语言之间的数据是无法直接交互的,我们想要解决这个问题

就需要将不同语言之间传输的数据做一个统一规范,而json是目前最流行的数据格式

一、json是什么

json 是一种数据交换格式,主要是将要传输的数据转换为json特有的格式

其他人拿到这个json数据后,可以通过数据反向转换得到转换前的数据

这样大家都将数据转为json格式,谁用就拿过来转换为自己识别的数据即可

json数据格式说明

JSON 依赖key-value 键值对形式来保存数据,而“键值对”组合中的键名

写在前面,并且用双引号""包裹,使用冒号:分隔,然后紧跟值

案例 常见格式定义

//json格式key-value
{"firstName": "Json"}//包含数组的json,value通过方括号包裹
{"address":["北京","上海"]}  //存放多个json,通过逗号分割
[{"name":"tom"},{"haha":"test"}]

当我们不确定这个格式是否正确,可以找个解析的网站去查看

https://www.json.cn/

 案例2  当有多个用户信息时逗号分割

[
{"name":"韩梅梅","age":20,"address":["上海","北京"]},
{"name":"李雷","age":26,"address":["山西","北京"]}
]

自动排列效果

[{"name":"韩梅梅","age":20,"address":["上海","北京"]},{"name":"李雷","age":26,"address":["山西","北京"]}
]

二、json序列化

json序列化是指,将语言中键值对类型的数据转换为json字符串

比如go语言中的结构体、map、数组、切片等,转换为json的格式被称为格式化

登陆标准库文档

https://studygolang.com/pkgdoc

有一个叫 encoding/json 的包是用于处理json字符串的

 根据开篇的提示找到Marshal与Unmarshal 函数,他们是用于正反向转换json用的

func Marshal(v interface{}) ([]byte, error)//通过文档得知,Marshal函数接收的是一个空接口类型
//意思是我们可以将go的任意类型的数据传入进去
//而返回值是一个byte的切片,以及error

1  结构体序列化

package mainimport ("encoding/json""fmt"
)type Monster struct{   //我们先定义一个结构体Name stringAge intBirthady stringSal float64Skill string
}func main(){monster := Monster{        //实例化结构体Name: "牛魔王",Age: 500,Birthady: "2011-11-11",Sal: 8000.0,Skill: "牛魔拳",}data,err := json.Marshal(&monster)  //通过json包下的Marshal函数对结构体进行转换if err != nil{fmt.Printf("序列化错误 err=%v",err)}//输出序列化的结果fmt.Printf("monster序列化后=%v\n",string(data))
}

返回

monster序列化后={"Name":"牛魔王","Age":500,"Birthady":"2011-11-11","Sal":8000,"Skill":"牛魔拳"}

2、map序列化

package mainimport ("encoding/json""fmt"
)func testMap(){//定义一个mapvar a map[string]interface{}a = make(map[string]interface{})a["name"] = "红孩儿"a["age"] = 30a["address"] = "火云洞"data,err := json.Marshal(a)   //将a这个map进行序列化if err != nil{fmt.Printf("序列化错误 err=%v",err)}fmt.Printf("a map序列化后=%v\n",string(data))
}
func main(){testMap()
}

返回

a map序列化后={"address":"火云洞","age":30,"name":"红孩儿"}

map类型是无序的,所以结果略有不同

3、切片序列化

package mainimport ("encoding/json""fmt"
)func testSlice(){var slice []map[string]interface{}   //定义一个切片,声明值为空接口var m1 map[string]interface{}m1 = make(map[string]interface{})m1["name"] = "jack"m1["age"] = "7"m1["address"] = "北京"slice = append(slice,m1)  //将m1加入切片var m2 map[string]interface{}m2 = make(map[string]interface{})m2["name"] = "tom"m2["age"] = "20"m2["address"] = "墨西哥"slice = append(slice,m2)  //将m2加入切片data,err := json.Marshal(slice)     //将切片进行序列化操作if err != nil{fmt.Printf("序列化错误 err=%v",err)}fmt.Printf("切片序列化后=%v\n",string(data))
}
func main(){testSlice()}

返回

切片序列化后=[{"address":"北京","age":"7","name":"jack"},{"address":"墨西哥","age":"20","name":"tom"}]

我们发现他变成一个数组了,因为他里面有多个json,多个json通过逗号分隔

4、基本数据类型 序列化

基本数据类型虽然没有键值对,但是也是可以做序列化的,但是没有意义

package mainimport ("encoding/json""fmt"
)
func testFloat64(){var num1 float64 = 23456.68//序列化data,err := json.Marshal(num1)if err != nil{fmt.Printf("序列化错误 err=%v",err)}fmt.Printf("普通数据类型序列化后=%v\n",string(data))
}
func main(){testFloat64()}

5、序列化数组

package mainimport ("encoding/json""fmt"
)
func testSlice(){var slice []map[string]interface{}      //定义一个切片,和上面切片类似var m1 map[string]interface{}           m1 = make(map[string]interface{})m1["name"] = "jack"m1["age"] = "7"m1["address"] = "北京"slice = append(slice,m1)var m2 map[string]interface{}m2 = make(map[string]interface{})m2["name"] = "tom"m2["age"] = "20"m2["address"] = [2]string{"墨西哥","夏威夷"}  //我们在某个值中定义为数组slice = append(slice,m2)data,err := json.Marshal(slice)if err != nil{fmt.Printf("序列化错误 err=%v",err)}fmt.Printf("切片序列化后=%v\n",string(data))
}
func main(){testSlice()}

返回

切片序列化后=[{"address":"北京","age":"7","name":"jack"},{"address":["墨西哥","夏威夷"],"age":"20","name":"tom"}]

三、标签

我们上面序列化结构体的时候,实际上就是把字段的key作为json的key使用

但在浏览器中我们更希望接收到的是首字母小写的字段,为了不破坏结构体调用,使用标签

package mainimport ("encoding/json""fmt"
)
//定义一个结构体
type Monster struct{Name string `json:"xxx_name"` //我们在定义结构体的时候,设置好tag json的一个标签Age int     `json:"xxx_age"`  //这样在转换时,就会转换为小写Birthady stringSal float64Skill string
}func testStruct(){monster := Monster{Name: "牛魔王" ,Age: 500,Birthady: "2011-11-11",Sal: 8000.0,Skill: "牛魔拳",}data,err := json.Marshal(&monster)if err != nil{fmt.Printf("序列化错误 err=%v",err)}fmt.Printf("monster序列化后=%v\n",string(data))
}func main(){testStruct()}

返回

monster序列化后={"xxx_name":"牛魔王","xxx_age":500,"Birthady":"2011-11-11","Sal":8000,"Skill":"牛魔拳"}

我们在结构体后面添加别名,这样在序列化时导出的就是别名的字段了

我们不能直接将字段定义为小写,这样会影响到其他的包进行调用

四、反序列化

就是将我们上面转换的json,重新转换为我们go所使用的数据类型

func Unmarshal(data []byte, v interface{}) error//传入的值是一个切片类型
//后面的v interface是指定我们用于接收json数据的结构体
//是否接收成功返回一个error的值

1、json转换为结构体

package mainimport ("encoding/json""fmt"
)
//定义一个结构体,必须要有这个结构体才能去反序列化到结构体
type Monster struct{Name stringAge intBirthady stringSal float64Skill string
}func unmarshalStruct(){//我们将这个json写入到变量,不过因为他本身有双引号,这里通过反斜杠将双斜杠转义//在实际开发中,这个str的字符串是通过前端POST上传或者读取文件得到的str := "{\"Name\":\"牛魔王\",\"Age\":500,\"Birthady\":\"2011-11-11\",\"Sal\":8000,\"Skill\":\"牛魔拳\"}"var monster Monster       //定义一个结构体,去接收反序列化json的结果err := json.Unmarshal([]byte(str),&monster)  //反序列化,通过[]byte(str)类型断言将str转换为切片if err != nil{fmt.Printf("unmarshal err=%v\n",err)}fmt.Printf("反序列化后 monster=%v",monster)
}func main(){unmarshalStruct()
}

返回

反序列化后 monster={牛魔王 500 2011-11-11 8000 牛魔拳}

2、json转换为map

package mainimport ("encoding/json""fmt"
)
func unmarshalMap(){str := "{\"address\":\"火云洞\",\"age\":30,\"name\":\"红孩儿\"}"var a map[string]interface{}  //定义一个map,必须和要转换的json之前的数据类型相同//反序列化时,Unmarshal已经封装了make动作,这里就不make了err := json.Unmarshal([]byte(str),&a)  //反序列化,必须传入&a才可使用if err != nil{fmt.Printf("unmarshal err=%v\n",err)}fmt.Printf("反序列化map后 a=%v",a)
}func main(){unmarshalMap()
}

返回

反序列化map后 a=map[address:火云洞 age:30 name:红孩儿]

3、json反序列化成切片

package mainimport ("encoding/json""fmt"
)
func unmarshalSclice(){str := "[{\"address\":\"北京\",\"age\":\"7\",\"name\":\"jack\"}," +"{\"address\":\"墨西哥\",\"age\":\"20\",\"name\":\"tom\"}]"var slice []map[string]interface{}   //定义一个切片,同样无需序列化err := json.Unmarshal([]byte(str),&slice)if err != nil{fmt.Printf("unmarshal err=%v\n",err)}fmt.Printf("反序列化slice后 slice=%v",slice)
}
func main(){unmarshalSclice()
}

返回

反序列化slice后 slice=[map[address:北京 age:7 name:jack] map[address:墨西哥 age:20 name:tom]]

小结说明

1、在反序列化一个json串时,要确保反序列化后的数据类型和原来序列化前的数据类型一致
2、上面的str是为了测试,在实际中是通过其他程序return过来,或者tcp传输过来的,不需要反斜杠去转义双引号

Golang学习(二十九)序列化和反序列化相关推荐

  1. Java多线程学习二十九:AtomicInteger(原子类) 和 synchronized 的异同点?

    原子类和 synchronized 关键字都可以用来保证线程安全,在本课时中,我们首先分别用原子类和 synchronized 关键字来解决一个经典的线程安全问题,给出具体的代码对比,然后再分析它们背 ...

  2. Golang学习(二十四)家庭记账项目

    一.项目开发流程 需求分析-->设计阶段-->实现阶段(代码)-->测试阶段-->实施阶段-->维护阶段 二.项目需求说明 1.模拟实现基于文本界面的 <家庭记账软 ...

  3. Golang 学习二十五(UDP 编程)

    文章目录 1. 服务端配置 2. 客户端配置 3. 实现双向聊天 4. 优化多客户端实现通讯 UDP 是用户数据报协议,是一种无连接传输协议,不需要建立连接就可以直接发送和接收数据,属于不可靠的,没有 ...

  4. ballerina 学习二十九 数据库操作

    ballerina 数据操作也是比较方便的,官方也我们提供了数据操作的抽象,但是我们还是依赖数据库驱动的. 数据库驱动还是jdbc模式的 项目准备 项目结构 ├── mysql_demo │ ├── ...

  5. python学习 (二十九) range函数

    1:list函数可以将其他类型转成list. print(list(range(0, 10))) 2: list函数把元组转成list t = (1, 3, 3, 5) print(list(t)) ...

  6. OpenGL学习二十九:模板缓冲区与模板测试

    帧缓冲区有许多缓冲区构成,这些缓冲区大致分为: 颜色缓冲区:用于绘图的缓冲区,它包含了颜色索引或者RGBA颜色数据. 深度缓冲区:存储每个像素的深度值,当启动深度测试时,片段像素深度值和深度缓冲区深度 ...

  7. 风炫安全Web安全学习第三十九节课 反序列化漏洞基础知识

    风炫安全Web安全学习第三十九节课 反序列化漏洞基础知识 反序列化漏洞 0x01 序列化相关基础知识 0x01 01 序列化演示 序列化就是把本来不能直接存储的数据转换成可存储的数据,并且不会丢掉数据 ...

  8. JavaScript学习(二十九)—JS常用的事件

    JavaScript学习(二十九)-JS常用的事件 一.页面相关事件 onload事件:当页面中所有的标签都加载完成后厨房该事件,格式:window.onload <body><sc ...

  9. Socket通信学习(二):序列化与反序列化

    Socket通信学习(二):序列化与反序列化 HoloLens的开发最近需要用到Socket通信,所以创建本系列进行记录,欢迎大家批评指正! 前言 Socket通信的默认发送的数据为byte[]类型, ...

最新文章

  1. TextView-- 测量文字宽度
  2. 瑞士电信vCPE商用落地 华三通信NFV方案成最大功臣
  3. guava和commons_使用Guava CharMatcher和Apache Commons Lang StringUtils确定字符串中字符或整数的存在...
  4. putil:一个用于获得处理器和系统相关信息的模块
  5. arch linux 树莓派,树莓派上安装配置Archlinux
  6. Android Studio 使用笔记:快捷键
  7. C#网站发布在IIS10上,Access数据库读取为空白的解决方案
  8. 16QAM matlab/simulink仿真
  9. 关于gotoxy函数
  10. scrapy中文文档基础知识
  11. 安装SQL 2000 企业版
  12. 动态代理的中介出租房屋
  13. CentOS下常用软件开机自启动脚本
  14. 一键式统计6.0季报测试
  15. 《Fundamentals of Computer Grahpics》虎书第三版翻译——第四章 光线追踪
  16. 面向对象:对象的概念
  17. 针对chromium IME的外接输入法框架
  18. Shader实现喷射蜘蛛网特效
  19. Win10连接Bose QC30 显示已配对但连接失败
  20. 2018年计算机考研真题及参考答案

热门文章

  1. 软件需求与软件需求规约
  2. Error (10267)
  3. SEO 网站排名优化(资源收藏,用得着时看看)
  4. android 打包aar,和引入aar
  5. 详解体温枪研发到生产出售需要的资质认证流程
  6. Educational Codeforces Round 67 (Rated for Div. 2)(D思维题 线段树/E树形dp(换根dp) 二次扫描与换根法)
  7. 什么是SFTP,看这篇就够了 ^^
  8. one morning of Saturday
  9. Spark中dataframe里data.drop()和data.na.drop()的区别
  10. 与程序猿谈恋爱后,我不得不做心机婊