go語言序列化及反序列化

參考文章:
go 官方package: https://blog.golang.org/json
特別好的文章:理解 Go 中的 JSON

JSON是一種輕量級的數據交換格式,常用在前後端數據交換,go的 encoding/json 提供了對json的支持

一、序列化

GO提供了 Marshal 方法:Go Struct轉換爲JSON對象,函數簽名:

func Marshal(v interface{}) ([]byte, error)

舉例:

type Person struct {
	Name   string
	Gender string
	Age    uint32
}

	// 默認初始化
	p := Person{"a", "male", 23}
	fmt.Println(p)
	fmt.Printf("%v\n", p) //{a male 23}

	// 指定成員初始化
	p1 := Person{Name: "wsq", Gender: "male"}
	fmt.Println(p1) //{wsq male 0}

	// 序列化
	b, _ := json.Marshal(p)
	fmt.Println(string(b)) //{"Name":"a","Gender":"male","Age":23}
}
  • 只支持struct中導出的field才能被序列化,即首字母大寫的field
  • GO中不是所有類型都支持序列化,其中key只支持string
  • 無法對channel,complex,function序列化
  • 數據中如存在循環引用,不支持序列化,因爲會遞歸。
  • pointer序列化後是其指向的值或者是nil
Struct Tag
指定 JSON filed name

序列化後的json串中的name一般爲小寫,我們通過struct tag實現

指定field爲empty

使用omitempty告訴Marshal函數,如field對應類型爲zero-value,那麼序列化的json對象中不包含此field

跳過field

僅使用"-"表示跳過指定的field,保護某些字段不被序列化

type Person struct {
	Name   string `json:"name"`
	Gender string `json:"gender"`
	Age    uint32 `json:"age,omitempty"`
	Passwd string `json:"-"`
}

	// 默認初始化
	p := Person{"a", "male", 23, "mimi"}
	fmt.Println(p)
	fmt.Printf("%v\n", p) //{a male 23}

	// 指定成員初始化
	p1 := Person{Name: "wsq", Gender: "male"}
	fmt.Println(p1) //{wsq male 0}

	// 序列化
	b, _ := json.Marshal(p)
	fmt.Println(string(b)) //{"Name":"a","Gender":"male","Age":23}

	// 反序列化
	var pp Person
	err := json.Unmarshal(b, &pp)
	if err != nil {
		errors.New("unmarshal error")
	}
	fmt.Printf("%T, %v\n", pp, pp)

	// Struct Tag
	// 指定JSON的field name
	c, _ := json.Marshal(p)
	fmt.Println(string(c)) //{"name":"a","gender":"male","age":23}

	// 指定field是empty時的行爲
	d, _ := json.Marshal(p1)
	fmt.Println(string(d)) //{"name":"wsq","gender":"male"}
	// 跳過指定field
	importPerson := Person{Name: "wsq", Passwd: "password"}
	importPersonMar, _ := json.Marshal(importPerson)
	fmt.Println(string(importPersonMar)) //{"name":"wsq","gender":""}

二、反序列化

發序列化函數 Unmarshal ,函數簽名:

func Unmarshal(data []byte, v interface{}) error

此時,我們需要創建一個可序列化的byte切片,將其轉換爲struct。
默認的json支持:bool, float64, string,nil幾種Go類型

反序列化處理未知JSON數據格式

使用interface{}存儲
舉例:

    b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
	var f interface{}
	err := json.Unmarshal(b, &f)
	if err != nil {
		errors.New("unmarshal error")
	}
	fmt.Printf("%T, %v\n", f, f)

輸出:

類型: map[string]interface {}
內容: map[Age:6 Name:Wednesday Parents:[Gomez Morticia]]

可以發現,此時keystring類型,value是存儲在interface {}中的,我們可以通過type assertion獲取:

	m := f.(map[string]interface{})
	for k, v := range m {
		switch vv := v.(type) {
		case string:
			fmt.Println(k, "is string", vv)
		case float64:
			fmt.Println(k, "is float64", vv)
		case []interface{}:
			fmt.Println(k, "is an array:")
			for i, u := range vv {
				fmt.Println(i, u)
			}
		default:
			fmt.Println(k, "is of a type I don't know how to handle")
		}
	}
反序列化處理slice、map、pointer

舉例:

type FamilyMember struct {
	Name    string
	Age     int
	Parents []string
}

func main() {
	b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
	var n FamilyMember
	json.Unmarshal(b, &n)
	fmt.Printf("%T, %v\n", n, n)

}

struct中存在一個slice類型,默認值爲nil。

  • 序列化時,若不爲nil,則解引用獲得其指向的值,然後序列化
  • 反序列化時首先對其初始化爲nil,之後再賦值

三、其他序列化函數

函數:

// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
    return &Encoder{w: w, escapeHTML: true}
}

// NewDecoder returns a new decoder that reads from r.
func NewDecoder(r io.Reader) *Decoder {
    return &Decoder{r: r}
}

func (enc *Encoder) Encode(v interface{}) error {
    // ...
}

舉例:
除了 marshal 和 unmarshal 函數,Go 還提供了 Decoder 和 Encoder 對 stream JSON 進行處理。

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	var err error
	person1 := Person{"張三", 30}
	// 編碼結果暫存到 buffer
	bytes1 := new(bytes.Buffer)
	_ = json.NewEncoder(bytes1).Encode(person1)
	if err == nil {
		fmt.Print("json.NewEncoder 編碼結果: ", string(bytes1.Bytes()))
	}

	// 解碼
	str2 := bytes1.String()
	var person2 Person
	// 創建一個 string reader 作爲參數
	err = json.NewDecoder(strings.NewReader(str2)).Decode(&person2)
	if err == nil {
		fmt.Println("json.NewDecoder 解碼結果: ", person2.Name, person2.Age)
	}

}
四、nest struct序列化
type App struct {
	Id string `json:"id"`
}

type Org struct {
	Name string `json:"name"`
}

type AppWithOrg struct {
	App
	Org
}

func main() {
	data := []byte(`
        {
            "id": "k34rAT4",
            "name": "My Awesome Org"
        }
    `)

	var b AppWithOrg

	json.Unmarshal(data, &b)
	fmt.Printf("%#v", b)

	a := AppWithOrg{
		App: App{
			Id: "k34rAT4",
		},
		Org: Org{
			Name: "My Awesome Org",
		},
	}
	data, _ = json.Marshal(a)
	fmt.Println(string(data))
}

vscode 工具相關
1. 刪除當前行ctrl + shift +k
2. vscode插件 String Manipulation 字符串轉換處理(駝峯、大寫開頭、下劃線等等)
   使用時ctrl+shift+p 輸入camel即可
3. ctrl+f5直接編譯簡單go文件

參考:http://lwenl.cn/?id=10
https://juejin.im/post/5d5cbc20f265da03ab425227
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章