美文网首页
[Go基础]Json在Go中的使用

[Go基础]Json在Go中的使用

作者: TOMOCAT | 来源:发表于2019-08-28 23:51 被阅读0次

    前言

    本文主要根据Go语言Json[1]、官方提供的Json and Go[2]go-and-json[3]整理的。

    Marshal

    Marshal提供对数据进行Json序列化的功能:

    func Marshal(v interface{}) ([]byte, error)
    
    type Message struct {
        Name string
        Body string
        Time int64
    }
    
    m := Message{"Alice", "Hello", 1294706395881547000}
    b, err := json.Marshal(m)
    //result
    b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
    

    注意事项:

    • Json对象只支持keystring,序列化Go map类型时必须是map[string]T的形式
    • channelcomplexfunction类型无法进行Json序列化
    • 无法序列化存在循环引用的数据,因为Marshal会陷入无限循环
    • 序列化pointer时是它指向的值(空指针序列化后为null

    Unmarshal

    func Unmarshal(data []byte, v interface{}) error
    
    var m Message
    err := json.Unmarshal(b, &m)
    
    //result:如果b包含符合结构体m的有效json格式,那么b中存储的数据就会保存到m中,比如:
    m = Message{
        Name: "Alice",
        Body: "Hello",
        Time: 1294706395881547000,
    }
    

    Struct Tags

    Golang中构建字段的时候我们可能会在结构体字段名后增加包含在倒引号(backticks)的Tag,如:

    type MyStruct struct {
        SomeField string `json:"some_field"`
    }
    
    • Json parser会根据Tag信息去解析字段值
    • Golang中可导出的字段首字母是大写的,这和我们在Json字段名常用小写是相冲突的,通过Tag可以有效解决这个问题
    • Tag信息中加入omitempty关键字后,序列化时自动忽视出现zero-value情形的字段。
      • numberzero-value为0
      • stringzero-valueempty string
      • mapslicepointerzero-valuenil
    type MyStruct struct {
        SomeField string `json:"some_field,omitempty"`
    }
    //在这个例子中,如果some_field为"":
    //加上omitempty后,序列化后的Json为{}
    //如果不加上omitempty,序列化后的Json为{"some_field": ""}
    
    • 跳过字段:在Tag中加入"-"
    type App struct {
        Id string `json:"id"`
        Password string `json:"-"`
    }
    

    嵌套字段

    Golang支持struct的嵌套,如:

    type App struct {
        Id string `json:"id"`
    }
    
    type Org struct {
        Name string `json:"name"`
    }
    
    type AppWithOrg struct {
        App
        Org
    }
    

    举个栗子,我们现在要将一个[]byte值反序列化为AppWithOrg的结构体:

    data := []byte(`
        {
            "id": "k34rAT4",
            "name": "My Awesome Org"
        }
    `)
    
    var appWithOrg AppWithOrg
    err := json.Unmarshal(data, &appWithOrg)
    
    app := appWithOrg.App
    org := appWithOrg.Org
    
    // AND/OR
    
    appId := appWithOrg.Id
    orgName := appWithOrg.Name
    

    指针

    如果结构体中出现pointer类型,当pointernil时通过dereferenced获取指针对应的值再进行序列化

    错误处理

    要注意检查MarshalUnmarshal返回的err参数,序列化时出现的错误会比较少见,但当Golang不知道如何将你的数据类型序列化为Json时就会报错(比如你尝试序列化包含nil pointer的数据类型时)。
    如果你不想处理Marshal出现的错误时,你可以将Marshal出现的错误转化为panic:

    func MustMarshal(data interface{}) []byte {
        out, err := json.Marshal(data)
        if err != nil {
            panic(err)
        }
    
        return out
    }
    

    反序列化任意Json数据

    如果你不知道你要解析的Json数据长啥样时,你可以将其反序列化为任意数据类型interface{}

    //将Json数据反序列化为任意类型
    var parsed interface{}
    err := json.Unmarshal(data, &parsed)
    
    //根据parsed数据类型做不同的逻辑处理
    switch parsed.(type) {
        case int:
            someGreatIntFunction(parsed.(int))
        case map:
            someMapThing(parsed.(map))
        default:
            panic("JSON type not understood")
    }
    
    //另一种类型判定逻辑
    intVal, ok := parsed.(int)
    if !ok {
        panic("JSON value must be an int")
    }
    

    一般情况下,你处理的Json对应的都是一个object,你可以将其反序列化为map[string]interface{}

    var parsed map[string]interface{}
    
    data := []byte(`
        {
            "id": "k34rAT4",
            "age": 24
        }
    `)
    
    err := json.Unmarshal(data, &parsed)
    
    //直接调用
    parsed["id"]
    //但使用之前仍然需要格式转换
    idString := parsed["id"].(string)
    

    除了object类型外,如果你清楚需要解析的Json格式,可以做如下反序列化:

    bool, for JSON booleans
    float64, for JSON numbers
    string, for JSON strings
    []interface{}, for JSON arrays
    map[string]interface{}, for JSON objects
    nil for JSON null
    

    Reference

    [1]https://golang.org/pkg/encoding/json/#example_Decoder
    [2]https://blog.golang.org/json-and-go
    [3]https://eager.io/blog/go-and-json/

    相关文章

      网友评论

          本文标题:[Go基础]Json在Go中的使用

          本文链接:https://www.haomeiwen.com/subject/vyavectx.html