josn
1.JOSN基本介绍
json(JavaScript Object Notation)是一种轻量级的数据交换格式。易于人阅读和编写,经典的使用方式采取key-val
形式来描述信息。
JSON易于机器解析和生成,并有效地提升网络传输效率,通常程序在网络传输时会先将数据(结构体、map等)序列化为json字符串;接收方得到json字符串后,在反序列化恢复成原来的数据类型(结构体、map等)。这种方式已然成为各个语言的标准。
json应用场景示意图
2.json数据格式说明
在JS语言中,一切变量/实例都可以是对象。因此,任何数据类型都可以通过JSON来表示,例如字符串、数字、数组、结构体、map等。
JOSN是采用键值对来保存信息,其十分灵活、扩展性高。例如:
- 表示一个变量,具有单一信息:
{"key1":val1}
例如:{"Name":"Josn"}
- 表示一个变量具有多信息:
{"key1":val1,"key2":val2,"key3":["val3_1","val3_2"]}
例如:{"Name":"Josn","age":18,"add":["上海","北京"]}
- josn描述多个变量:
[{...},{...}]
格式
例如:[{"Name":"Josn","age":18,"add":["上海","北京"]},{"Name":"Tom","age":18,"add":["武汉","成都"]}]
3.json数据在线解析
https://www.json.cn/网站可以验证一个json格式的数据是否正确。尤其是在编写比较复杂的json格式数据时,很有用。
4.json序列化
json序列化是指,将有key-value
结构的数据类型(比如结构体、map、切片)序列化成json字符串的操作。
应用案例:
介绍结构体、map、切片的序列化,其它数据类型的序列化类似。
使用到encoding/json
包中的func Marshal()
函数
func Marshal(v interface{}) ([]byte, error)
案例演示:
type Person struct {
Name string
Age int
Birthday string
Salary float64
}
// 结构体序列化
func (p *Person) testStruct() {
data, err := json.Marshal(p)
if err != nil {
log.Fatal(err)
}
fmt.Printf("person 序列化后=%v\n", string(data))
}
// map序列化
func testMap() {
m := make(map[string]interface{})
m["Name"] = "红孩儿"
m["age"] = 1500
m["address"] = [2]string{"火云洞", "火焰山"}
data, err := json.Marshal(m)
if err != nil {
log.Fatal(err)
}
fmt.Printf("map 序列化后=%v\n", string(data))
}
//切片序列化
func testSlice() {
slice := make([]map[string]interface{}, 2)
slice[0] = make(map[string]interface{})
slice[0]["Name"] = [2]string{"孙悟空", "斗战胜佛"}
slice[0]["Age"] = "5200"
slice[1] = make(map[string]interface{})
slice[1]["Name"] = "猪八戒"
slice[1]["address"] = [2]string{"高老庄", "西天"}
data, err := json.Marshal(slice)
if err != nil {
log.Fatal(err)
}
fmt.Printf("slice 序列化后=%v\n", string(data))
}
// 基本类型序列化
// 输出转为一个字符串,没特别意义
func testFloat64() {
f := 12.13
data, err := json.Marshal(f)
if err != nil {
log.Fatal(err)
}
fmt.Printf("float64 序列化后=%v\n", string(data))
}
func main() {
person := Person{
Name: "Tom",
Age: 18,
Birthday: "2003-09-08",
Salary: 5000,
}
person.testStruct()
testMap()
testSlice()
testFloat64()
}
Output
person 序列化后={“Name”:“Tom”,“Age”:18,“Birthday”:“2003-09-08”,“Salary”:5000}
map 序列化后={“Name”:“红孩儿”,“address”:[“火云洞”,“火焰山”],“age”:1500}
slice 序列化后=[{“Age”:“5200”,“Name”:[“孙悟空”,“斗战胜佛”]},{“Name”:“猪八戒”,“address”:[“高老庄”,“西天”]}]
float64 序列化后=12.13
json字符串传输时往往接收端希望获得的key
键值为小写或自定义,所以可以使用tag
标签形式进行处理。
案例:
type Person struct {
// 字段在json里的键为"name"且如果字段为空值将在对象中省略掉
Name string `json:"name,omitempty"`
// 字段在json里的键为"personAge"
Age int `json:"personAge"`
// 字段在json里的键为"Field"(默认值),但如果字段为空值会跳过;注意前导的逗号
Birthday string `json:",omitempty"`
// 字段被本包忽略
Salary float64 `json:"-"`
}
// 结构体序列化
func (p *Person) testStruct() {
data, err := json.Marshal(p)
if err != nil {
log.Fatal(err)
}
fmt.Printf("person 序列化后=%v\n", string(data))
}
func main() {
person := Person{
Name: "Tom",
Age: 18,
Birthday: "2003-09-08",
Salary: 5000,
}
person.testStruct()
}
Output:
person 序列化后={“name”:“Tom”,“personAge”:18,“Birthday”:“2003-09-08”}
5.json反序列化
json反序列化即:将json字符串反序列成对应的数据类型(比如结构体、map、切片等)的操作。
代码演示:
package main
import (
"encoding/json"
"fmt"
"log"
)
//将json字符串反序化成struct(在web中是没有结构体的)
type Person struct {
// 字段在json里的键为"name"且如果字段为空值将在对象中省略掉
Name string `json:"name,omitempty"`
// 字段在json里的键为"personAge"
Age int `json:"personAge"`
// 字段在json里的键为"Field"(默认值),但如果字段为空值会跳过;注意前导的逗号
Birthday string `json:",omitempty"`
// 字段被本包忽略
Salary float64 `json:"-"`
}
func (p *Person) unMarshalStruct(b []byte) {
err := json.Unmarshal(b, p)
if err != nil {
log.Fatal(err)
}
}
// 反序列化成map
func unMarshalMap() {
jsonBlob := []byte(`{"Name":"红孩儿","address":["火云洞","火焰山"],"age":1500}`)
var m map[string]interface{}
// 在返序列化map,不需要make,因为make操作封装到了Unmarshal函数中
//因此在参数列表中,即使m变量是应用类型,也需要加上&地址符,否则会报non-pointer
err := json.Unmarshal(jsonBlob, &m)
if err != nil {
log.Fatal(err)
}
fmt.Printf("反序列化后map=%v\n", m)
}
//切片序列化
func testSlice() []byte {
slice := make([]map[string]interface{}, 2)
slice[0] = make(map[string]interface{})
slice[0]["Name"] = [2]string{"孙悟空", "斗战胜佛"}
slice[0]["Age"] = "5200"
slice[1] = make(map[string]interface{})
slice[1]["Name"] = "猪八戒"
slice[1]["address"] = [2]string{"高老庄", "西天"}
data, err := json.Marshal(slice)
if err != nil {
log.Fatal(err)
}
return data
}
// 反序列化成Slice
func unMarshalSlice() {
data := testSlice()
slice := []map[string]interface{}{}
err := json.Unmarshal(data, &slice)
if err != nil {
log.Fatal(err)
}
fmt.Printf("反序列化后slice=%v\n", slice)
}
func main() {
person := Person{}
// josn字符串在项目开发中,是通过网络传输或读取文件获得到的
str := "{\"name\":\"Tom\",\"personAge\":18,\"Birthday\":\"2003-09-08\"}"
person.unMarshalStruct([]byte(str))
fmt.Printf("反序列化后 person=%v\n", person) //反序列化后 person={Tom 18 2003-09-08 0}
fmt.Printf("反序列化后 person.Age=%T\n", person.Age) //反序列化后 person.Age=int
unMarshalMap()
unMarshalSlice()
}
Output:
反序列化后 person={Tom 18 2003-09-08 0}
反序列化后 person.Age=int
反序列化后map=map[Name:红孩儿 address:[火云洞 火焰山] age:1500]
反序列化后slice=[map[Age:5200 Name:[孙悟空 斗战胜佛]] map[Name:猪八戒 address:[高老庄 西天]]]
案例总结/细节说明:
1.测试时可以先创建一个字符串str
包含json字符串信息,但需注意在赋值时,要注意转义符的使用(\"\"
),再将str
转换为[]byte
类型进行使用。
2.测试时,也可以直接采用[]byte
类型创建josn字符串信息,使用形式:
jsonBlob := []byte(`{"Name":"红孩儿","address":["火云洞","火焰山"],"age":1500}`)
3.在反序列化map、slice
类型时,定义变量后不需要进行make
操作,因为在unMarshal()
函数中封装了make
操作;但需注意的是,在输入的参数列表中,对于应用类型必须添加&
地址标识符,否则会出现因还没make
而导致无分配指针的错误发生。
4.反序列化一个json字符串时,要确保反序列化后的数据类型要和原来序列化前的数据类型一致。