zoukankan      html  css  js  c++  java
  • 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 = "yangshiyu@x.com"
        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
     
    }

      转自:http://www.cnblogs.com/yangshiyu/p/6942414.html

    https://www.cnblogs.com/52php/p/6518728.html

     
     
  • 相关阅读:
    ListView -————不能不说的秘密
    良好的开端是成功的第一步———构建程序
    你所不知道的windows窗体
    数据库查询终结版2———分组——连接
    数据库的终结版查询————你想知道吗?
    《官神》浏览闲看笔记
    坚信梦想,奋勇前进!____OS小题狂刷2333
    众里寻他千百度,蓦然回首,却见写者优先算法,她在书本寂静处!
    生产消费问题扩展——三个并发进程R,M,P和一个共享的循环缓冲区B的并发控制
    多生产者-多消费者-环形缓冲区问题
  • 原文地址:https://www.cnblogs.com/williamjie/p/9927281.html
Copyright © 2011-2022 走看看