golang json用法講解

簡介

json格式可以算我們日常最常用的序列化格式之一了,Go語言作爲一個由Google開發,號稱互聯網的C語言的語言,自然也對JSON格式支持很好。但是Go語言是個強類型語言,對格式要求極其嚴格而JSON格式雖然也有類型,但是並不穩定,Go語言在解析來源爲非強類型語言時比如PHP等序列化的JSON時,經常遇到一些問題諸如字段類型變化導致無法正常解析的情況,導致服務不穩定。所以本篇的主要目的

  1. 就是挖掘Golang解析json的絕大部分能力
  2. 比較優雅的解決解析json時存在的各種問題
  3. 深入一下Golang解析json的過程
  • Golang解析JSON之Tag篇

  1. 一個結構體正常序列化過後是什麼樣的呢?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

package main

import (

    "encoding/json"

    "fmt"

)

 

// Product 商品信息

type Product struct {

    Name      string

    ProductID int64

    Number    int

    Price     float64

    IsOnSale  bool

}

 

func main() {

    p := &Product{}

    p.Name = "Xiao mi 6"

    p.IsOnSale = true

    p.Number = 10000

    p.Price = 2499.00

    p.ProductID = 1

    data, _ := json.Marshal(p)

    fmt.Println(string(data))

}

 

 

//結果

{"Name":"Xiao mi 6","ProductID":1,"Number":10000,"Price":2499,"IsOnSale":true}

  2. 何爲Tag,tag就是標籤,給結構體的每個字段打上一個標籤,標籤冒號前是類型,後面是標籤名

1

2

3

4

5

6

7

8

9

10

11

// Product _

type Product struct {

    Name      string  `json:"name"`

    ProductID int64   `json:"-"// 表示不進行序列化

    Number    int     `json:"number"`

    Price     float64 `json:"price"`

    IsOnSale  bool    `json:"is_on_sale,string"`

}

 

// 序列化過後,可以看見

   {"name":"Xiao mi 6","number":10000,"price":2499,"is_on_sale":"false"}

  3. omitempty,tag裏面加上omitempy,可以在序列化的時候忽略0值或者空值

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

package main

 

import (

    "encoding/json"

    "fmt"

)

 

// Product _

type Product struct {

    Name      string  `json:"name"`

    ProductID int64   `json:"product_id,omitempty"`

    Number    int     `json:"number"`

    Price     float64 `json:"price"`

    IsOnSale  bool    `json:"is_on_sale,omitempty"`

}

 

func main() {

    p := &Product{}

    p.Name = "Xiao mi 6"

    p.IsOnSale = false

    p.Number = 10000

    p.Price = 2499.00

    p.ProductID = 0

 

    data, _ := json.Marshal(p)

    fmt.Println(string(data))

}

// 結果

{"name":"Xiao mi 6","number":10000,"price":2499}

  4. type,有些時候,我們在序列化或者反序列化的時候,可能結構體類型和需要的類型不一致,這個時候可以指定,支持string,number和boolean

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

package main

 

import (

    "encoding/json"

    "fmt"

)

 

// Product _

type Product struct {

    Name      string  `json:"name"`

    ProductID int64   `json:"product_id,string"`

    Number    int     `json:"number,string"`

    Price     float64 `json:"price,string"`

    IsOnSale  bool    `json:"is_on_sale,string"`

}

 

func main() {

 

    var data = `{"name":"Xiao mi 6","product_id":"10","number":"10000","price":"2499","is_on_sale":"true"}`

    p := &Product{}

    err := json.Unmarshal([]byte(data), p)

    fmt.Println(err)

    fmt.Println(*p)

}

// 結果

<nil>

{Xiao mi 6 10 10000 2499 true}

  • 下面講一講Golang如何自定義解析JSON,Golang自帶的JSON解析功能非常強悍

說明

很多時候,我們可能遇到這樣的場景,就是遠端返回的JSON數據不是你想要的類型,或者你想做額外的操作,比如在解析的過程中進行校驗,或者類型轉換,那麼我們可以這樣或者在解析過程中進行數據轉換

實例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

package main

 

import (

    "bytes"

    "encoding/json"

    "fmt"

)

 

// Mail _

type Mail struct {

    Value string

}

 

// UnmarshalJSON _

func (m *Mail) UnmarshalJSON(data []byte) error {

    // 這裏簡單演示一下,簡單判斷即可

    if bytes.Contains(data, []byte("@")) {

        return fmt.Errorf("mail format error")

    }

    m.Value = string(data)

    return nil

}

 

// UnmarshalJSON _

func (m *Mail) MarshalJSON() (data []byte, err error) {

    if m != nil {

        data = []byte(m.Value)

    }

    return

}

 

// Phone _

type Phone struct {

    Value string

}

 

// UnmarshalJSON _

func (p *Phone) UnmarshalJSON(data []byte) error {

    // 這裏簡單演示一下,簡單判斷即可

    if len(data) != 11 {

        return fmt.Errorf("phone format error")

    }

    p.Value = string(data)

    return nil

}

 

// UnmarshalJSON _

func (p *Phone) MarshalJSON() (data []byte, err error) {

    if p != nil {

        data = []byte(p.Value)

    }

    return

}

 

// UserRequest _

type UserRequest struct {

    Name  string

    Mail  Mail

    Phone Phone

}

 

func main() {

    user := UserRequest{}

    user.Name = "ysy"

    user.Mail.Value = "[email protected]"

    user.Phone.Value = "18900001111"

    fmt.Println(json.Marshal(user))

}

  

爲什麼要這樣?

如果是客戶端開發,需要開發大量的API,接收大量的JSON,在開發早期定義各種類型看起來是很大的工作量,不如寫 if else 判斷數據簡單暴力。但是到開發末期,你會發現預先定義的方式能極大的提高你的代碼質量,減少代碼量。下面實例1和實例2,誰能減少代碼一目瞭然

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

實例1,if else做數據校驗

// UserRequest _

type UserRequest struct {

    Name  string

    Mail  string

    Phone string

}

func AddUser(data []byte) (err error) {

    user := &UserRequest{}

    err = json.Unmarshal(data, user)

    if err != nil {

        return

    }

    //

    if isMail(user.Mail) {

        return fmt.Errorf("mail format error")

    }

 

    if isPhone(user.Phone) {

        return fmt.Errorf("phone format error")

    }

 

    // TODO

    return

}

 

實例2,利用預先定義好的類型,在解析時就進行判斷

// UserRequest _

type UserRequest struct {

    Name  string

    Mail  Mail

    Phone Phone

}

 

func AddUser(data []byte) {

    user := &UserRequest{}

    err = json.Unmarshal(data, user)

    if err != nil {

        return

    }

 

    // TODO

 

}

發佈了67 篇原創文章 · 獲贊 27 · 訪問量 36萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章