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, "\t", "")
    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("反序列化之前: \n\ts1 = %v \n\ts1.Name = %s\n\n", 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("反序列化之后: \n\ts1 = %v \n\ts1.Name = %s\n", 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM