首页 > 编程笔记 > Go语言笔记 阅读:43

golang json库序列化和反序列化(附带实例)

序列化是指将数据统一成一种数据格式,以便在不同的语言间传递。

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 的功能就是实现字段名到键名的映射。

相关文章