golang json库序列化和反序列化(附带实例)
序列化是指将数据统一成一种数据格式,以便在不同的语言间传递。
JSON 是跨语言的数据格式,golang 的标准库 encoding/json 允许对结构体执行 JSON 格式的序列化和反序列化。
标准库 encoding/json 使用了反射,这会导致它的性能不太好,并且在编写返回 JSON 响应的 API 或微服务时会损失性能。如果是性能要求很高的场景,建议使用第三方包实现。
反序列化时需要注意以下两种情况:
1) 如果变量 mysql 初始化后返回的是非指针类型的结构体,如 mysql:=Mariadb{},那么后面的反序列会报错:
2) 如果结构体的成员后面有 JSON 的 tag,那么会以 JSON 的 tag 作为键。
示例代码如下:
JSON 是跨语言的数据格式,golang 的标准库 encoding/json 允许对结构体执行 JSON 格式的序列化和反序列化。
golang JSON序列化
可以使用标准库 encoding/json 对结构体进行序列化,示例代码如下:type MySQL struct { Version string IP string port int } //测试JSON的序列化 func TestSerialize(t *testing.T) { mysql := new(MySQL) mysql.Version = "8.0.21" mysql.IP = "192.168.0.100" mysql.port = 13306 //将变量mysql序列化成JSON格式的字节切片 b,err := json.Marshal(mysql) if err !=nil { fmt.Println("marshal err: ",err.Error()) return } //将JSON字节数组转换成字符串输出 fmt.Println("marshal json:",string(b)) }执行结果为:
marshal json: {"Version":"8.0.21","IP":"192.168.0.100"}
以上代码在输出 JSON 格式的字符串时,没有输出 port 的信息。这是因为在结构体的定义中,port 的首字母是小写的,表示在被外部包调用时不可导出。标准库 encoding/json 使用了反射,这会导致它的性能不太好,并且在编写返回 JSON 响应的 API 或微服务时会损失性能。如果是性能要求很高的场景,建议使用第三方包实现。
golang JSON反序列化
使用标准库 encoding/json 还可以对结构体进行反序列化,示例代码如下:// 反序列化结构体 func TestDeSerializeStruct(t *testing.T) { type Mariadb struct { Version string IP string Port int } mysql:=new(Mariadb) jsonStr:=`{"Version":"8.0.21","IP":"192.168.0.100"}` err:=json.Unmarshal([]byte(jsonStr),mysql) if err!=nil{ fmt.Println("DeSerializeStruct err:",err.Error()) return } fmt.Printf("%T , %v",mysql,mysql) }执行结果为:
*jsont_test.Mariadb , &{8.0.21 192.168.0.100 0}
反序列化时需要注意以下两种情况:
1) 如果变量 mysql 初始化后返回的是非指针类型的结构体,如 mysql:=Mariadb{},那么后面的反序列会报错:
DeSerializeStruct err: json: Unmarshal(non-pointer jsont_test.Mariadb)
2) 如果结构体的成员后面有 JSON 的 tag,那么会以 JSON 的 tag 作为键。
提示,映射和 JSON 的数据格式类似,都是键值对,因此映射的序列化与反序列化都可以参考 JSON。
golang使用tag
golang 还有一个名为标签(tag)的概念,序列化时可将 tag 作为 JSON 的键使用。示例代码如下:
type MySQLHA struct { Version string `json:"db_version"` HA string `json:"ha_arch"` Port int `json:"proxy_port"` } //序列化结构体,使用tag func TestSerializeStructWithTag(t *testing.T) { mysql := new(MySQLHA) mysql.Version = "8.0.21" mysql.HA = "MGR" mysql.Port = 6033 //将变量mysql序列化成JSON格式的字节切片 b,err := json.Marshal(mysql) if err !=nil { fmt.Println("marshal err: ",err.Error()) return } //将json字节数组转化成字符串输出 fmt.Println("marshal json:",string(b)) }执行结果为:
marshal json: {"db_version":"8.0.21","ha_arch":"MGR","proxy_port":13306}
从上述输出结果中可以看出,JSON 字符串的键不再是结构体中定义的成员,而是成员后面的 json:"xxx" 属性。tag 常用于结构体的成员和业务表的字段名不一致的场景。在这种场景下,tag 的功能就是实现字段名到键名的映射。