Golang学习(二十九)序列化和反序列化

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

就需要将不同语言之间传输的数据做一个统一规范,而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 main

import (
	"encoding/json"
	"fmt"
)

type Monster struct{   //我们先定义一个结构体
	Name string
	Age int
	Birthady string
	Sal float64
	Skill 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 main

import (
	"encoding/json"
	"fmt"
)

func testMap(){
	//定义一个map
	var a map[string]interface{}
	a = make(map[string]interface{})
	a["name"] = "红孩儿"
	a["age"] = 30
	a["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 main

import (
	"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 main

import (
	"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 main

import (
	"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 main

import (
	"encoding/json"
	"fmt"
)
//定义一个结构体
type Monster struct{
	Name string `json:"xxx_name"` //我们在定义结构体的时候,设置好tag json的一个标签
	Age int     `json:"xxx_age"`  //这样在转换时,就会转换为小写
	Birthady string
	Sal float64
	Skill 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 main

import (
	"encoding/json"
	"fmt"
)
//定义一个结构体,必须要有这个结构体才能去反序列化到结构体
type Monster struct{
	Name string
	Age int
	Birthady string
	Sal float64
	Skill 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 main

import (
	"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 main

import (
	"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传输过来的,不需要反斜杠去转义双引号

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值