Golang的序列化-JSON篇

            Golang的序列化-JSON篇

                               作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

 

 

 

一.序列化概述

1>.什么是序列化

  数据在网络传输前后要进行序列化和反序列化。目的是将复杂的数据类型按照统一、简单且高效的形式转储,以达到网络传输的目的。

  除了在网络传输,有的数据存储到本地也是为了其它语言使用方便,通常也会使用相对来说较为通用的数据格式来存储,这就是我们常说的序列化,反序列化就是将数据按照规定的语法格式进行解析的过程。

2>.什么是JSON

  JSON采用完全独立于语言的文本格式,但是也使用了类似于 C 语言家族的习惯(包括 C、C++、C#、Java、JavaScript、Perl、Python、go等)。这些特性使JSON成为理想的数据交换语言。 

  易于人阅读和编写,同时也易于机器解析和生成(一般用于提升网络传输速率)。目前,json已经成为主流的数据格式。
  JSON的特性:
    a).JSON解析器和JSON库支持许多不同的编程语言。
    b).JSON文本格式在语法上与创建JavaScript对象的代码相同。由于这种相似性,无需解析器,JavaScript程序能够使用内建的eval()函数,用JSON数据来生成原生的JavaScript对象。
    c).JSON 是存储和交换文本信息的语法。比 XML 更小、更快,更易解析。
    d).JSON 具有自我描述性,语法简洁,易于理解。
    e).JSON数据主要有两种数据结构,一种是键
/值,另一种是数组的形式来表示。

  博主推荐阅读:
    http:
//www.json.org.cn/

 

二.JSON序列化案例

1>.结构体序列化

package main

import (
    "encoding/json"
    "fmt"
)

/**
定义需要结构体
*/
type Teacher struct {
    Name    string
    ID      int
    Age     int
    Address string
}

func main() {
    s1 := Teacher{
        Name:    "Jason Yin",
        ID:      001,
        Age:     18,
        Address: "北京",
    }

    /**
    使用“encoding/json”包的Marshal函数进行序列化操作,其函数签名如下所示:
        func Marshal(v interface{}) ([]byte, error)
    以下是对Marshal函数参数相关说明:
        v:
            该参数是空接口类型。意味着任何数据类型(int、float、map,结构体等)都可以使用该函数进行序列化。
        返回值:
            很明显返回值是字节切片和错误信息
    */
    //data, err := json.Marshal(&s1)

    /**
    Go语言标准库的"encoding/json"包还提供了另外一个方法:MarshalIndent。
    该方法的作用与Marshall作用相同,只是可以通过方法参数,设置前缀、缩进等,对Json多了一些格式处理,打印出来比较好看。
    */
    data, err := json.MarshalIndent(s1, "	", "")
    if err != nil {
        fmt.Println("序列化出错,错误原因: ", err)
        return
    }

    /**
    查看序列化后的json字符串
    */
    fmt.Println("序列化之后的数据为: ", string(data))
}
MarshalIndent函数案例(了解即可)
package main

import (
    "encoding/json"
    "fmt"
)

/**
定义需要结构体
*/
type Teacher struct {
    Name    string
    ID      int
    Age     int
    Address string
}

func main() {
    s1 := Teacher{
        Name:    "Jason Yin",
        ID:      001,
        Age:     18,
        Address: "北京",
    }

    /**
    使用“encoding/json”包的Marshal函数进行序列化操作,其函数签名如下所示:
        func Marshal(v interface{}) ([]byte, error)
    以下是对Marshal函数参数相关说明:
        v:
            该参数是空接口类型。意味着任何数据类型(int、float、map,结构体等)都可以使用该函数进行序列化。
        返回值:
            很明显返回值是字节切片和错误信息
    */
    data, err := json.Marshal(&s1)    //注意哈,这里传递的是引用地址哟~
    if err != nil {
        fmt.Println("序列化出错,错误原因: ", err)
        return
    }

    /**
    查看序列化后的json字符串
    */
    fmt.Println("序列化之后的数据为: ", string(data))
}

2>.Map序列化

package main

import (
    "encoding/json"
    "fmt"
)

func main() {

    var s1 map[string]interface{}

    /**
    使用make函数初始化map以开辟内存空间
    */
    s1 = make(map[string]interface{})

    /**
    map赋值操作
    */
    s1["name"] = "Jason Yin"
    s1["age"] = 20
    s1["address"] = [2]string{"北京", "陕西"}

    /**
    将map使用Marshal()函数进行序列化
    */
    data, err := json.Marshal(s1)
    if err != nil {
        fmt.Println("Marshal err: ", err)
        return
    }

    /**
    查看序列化后的json字符串
    */
    fmt.Println("序列化之后的数据为: ", string(data))

}

3>.切片(sllice)序列化

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    /**
    创建一个类似于map[string]interface{}的切片
    */
    var s1 []map[string]interface{}

    /**
    使用make函数初始化map以开辟内存空间,
    */
    m1 := make(map[string]interface{})

    /**
    为map进行赋值操作
    */
    m1["name"] = "李白"
    m1["role"] = "打野"

    m2 := make(map[string]interface{})
    m2["name"] = "王昭君"
    m2["role"] = "中单"

    m3 := make(map[string]interface{})
    m3["name"] = "程咬金"
    m3["role"] = "上单"

    /**
    将map追加到切片中
    */
    s1 = append(s1, m3, m2, m1)

    data, err := json.Marshal(s1)
    if err != nil {
        fmt.Println("序列化出错,错误原因: ", err)
        return
    }

    /**
    查看序列化后的数据
    */
    fmt.Println(string(data))
}

4>.数组序列化

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    /**
    定义数组
    */
    var s1 = [5]int{9, 5, 2, 7, 5200}
    /**
    将数组使用Marshal函数进行序列化
    */
    data, err := json.Marshal(s1)
    if err != nil {
        fmt.Println("序列化错误: ", err)
        return
    }
    /**
    查看序列化后的json字符串
    */
    fmt.Println("数组序列化后的数据为: ", string(data))
}

5>.基础数据类型序列化

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    /**
    定义基础数据类型数据
    */
    var (
        Surname       = ''
        Name          = "尹正杰"
        Age           = 18
        Temperature   = 35.6
        HubeiProvince = false
    )

    /**
    将基础数据类型进行序列化操作
    */
    surname, _ := json.Marshal(Surname)
    name, _ := json.Marshal(Name)
    age, _ := json.Marshal(Age)
    temperature, _ := json.Marshal(Temperature)
    hubeiProvince, _ := json.Marshal(HubeiProvince)

    /**
    查看序列化后的json字符串
    */
    fmt.Println("Surname序列化后的数据为: ", string(surname))
    fmt.Println("Name序列化后的数据为: ", string(name))
    fmt.Println("Age序列化后的数据为: ", string(age))
    fmt.Println("Temperature序列化后的数据为: ", string(temperature))
    fmt.Println("HubeiProvince序列化后的数据为: ", string(hubeiProvince))
}

三.JSON反序列化案例

1>.结构体反序列化

package main

import (
    "encoding/json"
    "fmt"
)

type People struct {
    Name    string
    Age     int
    Address string
}

func main() {
    /**
    以Json数据为例,我们接下来要对该数据进行反序列化操作。
    */
    p1 := `{"Name":"Jason Yin","Age":18,"Address":"北京"}`

    var s1 People
    fmt.Printf("反序列化之前: 
	s1 = %v 
	s1.Name = %s

", s1, s1.Name)

    /**
    使用encoding/json包中的Unmarshal()函数进行反序列化操作,其函数签名如下:
        func Unmarshal(data []byte, v interface{}) error
    以下是对函数签名的参数说明:
        data:
            待解析的json编码字符串
        v:
            解析后传出的结果,即用来可以容纳待解析的json数据容器.
    */
    err := json.Unmarshal([]byte(p1), &s1)
    if err != nil {
        fmt.Println("反序列化失败: ", err)
        return
    }

    /**
    查看反序列化后的结果
    */
    fmt.Printf("反序列化之后: 
	s1 = %v 
	s1.Name = %s
", s1, s1.Name)

}

2>.map反序列化

package main

import (
    "encoding/json"
    "fmt"
)

func main() {

    m1 := `{"address":["北京","陕西"],"age":20,"name":"Jason Yin"}`

    /**
    定义map变量,类型必须与之前序列化的类型完全一致。
    */
    var s1 map[string]interface{}
    fmt.Println("反序列化之前:s1 =", s1)

    /**
    温馨提示:
        不需要使用make函数给m初始化,开辟空间。这是因为在反序列化函数Unmarshal()中会判断传入的参数2,如果是map类型数据,会自动开辟空间。相当于是Unmarshal()函数可以帮助我们做make操作。
        但传参时需要注意,Unmarshal的第二个参数,是用作传出,返回结果的。因此必须传m的地址值。
    */
    err := json.Unmarshal([]byte(m1), &s1)
    if err != nil {
        fmt.Println("反序列化失败,错误原因: ", err)
        return
    }

    fmt.Println("反序列化之后:s1 =", s1)
}

3>.切片(slice)反序列化

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    s1 := `[{"name":"王昭君","role":"中单"},{"name":"李白","role":"打野"}]`

    var slice []map[string]interface{}
    fmt.Println("反序列化之前:slice =", slice)

    /**
    实现思路与前面两种的实现完全一致,这里不再赘述。

    温馨提示:
        反序列化json字符串时,务必确保反序列化传出的数据类型,与之前序列化的数据类型完全一致。
    */
    err := json.Unmarshal([]byte(s1), &slice)
    if err != nil {
        fmt.Println("反序列化失败,错误原因: ", err)
        return
    }

    fmt.Println("反序列化之后:slice =", slice)
}

四.结构体标签(tag)序列化

package main

import (
    "encoding/json"
    "fmt"
)

/**
结构体的字段除了名字和类型外,还可以有一个可选的标签(tag),它是一个附属于字段的字符串,可以是文档或其他的重要标记。
比如在我们解析json或生成json文件时,常用到encoding/json包,它提供一些默认标签。
定义结构体时,可以通过这些默认标签来设定结构体成员变量,使之在序列化后得到特殊的输出。
*/
type Student struct {
    /**
    “-”标签:
        作用是不进行序列化,效果和将结构体字段首字母写成小写一样。
    */
    Name string `json:"-"`

    /**
    string标签:
        这样生成的json对象中,ID的类型转换为字符串
    */
    ID int `json:"id,string"`

    /**
    omitempty标签:
        可以在序列化的时候忽略0值或者空值;
    */
    Age int `json:"AGE,omitempty"`

    /**
    可以将字段名称进行重命名操作:
        比如下面的案例就是将"Address"字段重命名为"HomeAddress"哟~
    */
    Address string `json:"HomeAddress"`

    /**
    由于该字段首字母是小写,因此该字段不参与序列化哟~
    */
    score int
    Hobby string
}

func main() {
    s1 := Student{
        Name: "Jason Yin",
        ID:   001,
        //Age:     18,
        Address: "北京",
        score:   100,
        Hobby:   "中国象棋",
    }

    data, err := json.Marshal(s1)
    if err != nil {
        fmt.Println("序列化出错,错误原因: ", err)
        return
    }
    fmt.Println("序列化结果: ", string(data))
}

五.博主推荐阅读

  Golang的序列化-Gob篇:
    https://www.cnblogs.com/yinzhengjie2020/p/12735277.html
原文地址:https://www.cnblogs.com/yinzhengjie2020/p/12731049.html