zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    mktemp -t -d用法
    使用getopts处理输入参数
    linux中$1的意思
    linux中的set -e 与set -o pipefail
    在windows 7 和linux上安装xlwt和xlrd
    nginx map使用方法
    Linux crontab下关于使用date命令和sudo命令的坑
    东哥讲义
    ldapsearch使用
    date 命令之日期和秒数转换
  • 原文地址:https://www.cnblogs.com/yinzhengjie2020/p/12731049.html
Copyright © 2011-2022 走看看