西弗勒斯 發表於 2019-12-30 10:26:00

[go]灵活的处理json与go结构体

<ul>
<li>go数据结构与json数据结构对应( json.Unmarshal帮助手册)</li>
</ul>
<pre><code>
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
mapinterface{}, for JSON objects
nil for JSON nul


注: 手册里可以看到转json时, 常见选项的含义和例子.
</code></pre>
<ul>
<li>一些例子<br>
go by example: json</li>
</ul>
<pre><code>package main

import (
    "encoding/json"
    "fmt"
    "os"
)

type response1 struct {
    Page   int
    Fruits []string
}

type response2 struct {
    Page   int      `json:"page"`
    Fruits []string `json:"fruits"`
}

func main() {

    bolB, _ := json.Marshal(true)
    fmt.Println(string(bolB))

    intB, _ := json.Marshal(1)
    fmt.Println(string(intB))

    fltB, _ := json.Marshal(2.34)
    fmt.Println(string(fltB))

    strB, _ := json.Marshal("gopher")
    fmt.Println(string(strB))

    slcD := []string{"apple", "peach", "pear"}
    slcB, _ := json.Marshal(slcD)
    fmt.Println(string(slcB))

    mapD := mapint{"apple": 5, "lettuce": 7}
    mapB, _ := json.Marshal(mapD)
    fmt.Println(string(mapB))

    res1D := &amp;response1{
      Page:   1,
      Fruits: []string{"apple", "peach", "pear"}}
    res1B, _ := json.Marshal(res1D)
    fmt.Println(string(res1B))

    res2D := &amp;response2{
      Page:   1,
      Fruits: []string{"apple", "peach", "pear"}}
    res2B, _ := json.Marshal(res2D)
    fmt.Println(string(res2B))

    byt := []byte(`{"num":6.13,"strs":["a","b"]}`)

    var dat mapinterface{}

    if err := json.Unmarshal(byt, &amp;dat); err != nil {
      panic(err)
    }
    fmt.Println(dat)

    num := dat["num"].(float64)
    fmt.Println(num)

    strs := dat["strs"].([]interface{})
    str1 := strs.(string)
    fmt.Println(str1)

    str := `{"page": 1, "fruits": ["apple", "peach"]}`
    res := response2{}
    json.Unmarshal([]byte(str), &amp;res)
    fmt.Println(res)
    fmt.Println(res.Fruits)
   
    //上面unmarshal得到的都是字节数组,这里直接将字节数组写入流
    enc := json.NewEncoder(os.Stdout)
    d := mapint{"apple": 5, "lettuce": 7}
    enc.Encode(d)
}
</code></pre>
<ul>
<li>go数据类型转json: struct tag for json: 结构体转json时作用</li>
</ul>
<pre><code>
/*
Examples of struct field tags and their meanings:
// Field appears in JSON as key "myName".
Field int `json:"myName"`

// Field appears in JSON as key "myName" and
// the field is omitted from the object if its value is empty,
// as defined above.
Field int `json:"myName,omitempty"`

// Field appears in JSON as key "Field" (the default), but
// the field is skipped if empty.
// Note the leading comma.
Field int `json:",omitempty"`

// Field is ignored by this package.
Field int `json:"-"`

// Field appears in JSON as key "-".
Field int `json:"-,"
*/
</code></pre>
<pre><code>- 默认
type user struct {
        Name string
        Ageint
}

func main() {
        u := user{
                Name: "m1",
                Age:22,
        }
        b, _ := json.Marshal(u)
        fmt.Println(string(b))
}
// {"Name":"m1","Age":22}

</code></pre>
<pre><code>- json tag:

type user struct {
        Name string `json:"name"`
        Ageint    `json:"age"`
}

func main() {
        u := user{
                Name: "m1",
                Age:22,
        }
        b, _ := json.Marshal(u)
        fmt.Println(string(b))
}

// {"name":"m1","age":22}
</code></pre>
<pre><code>- struct实例缺少字段

type user struct {
        Name string `json:"name"`
        Ageint    `json:"age"`
}

func main() {
        u := user{
                Name: "m1",
        }
        b, _ := json.Marshal(u)
        fmt.Println(string(b))
}

// {"name":"m1","age":0}
</code></pre>
<pre><code>- josn tag: omitempty

//例子1:
type user struct {
        Name string `json:"name"`
        Age int `json:"age,omitempty"`
}

func main() {
        u := user{
                Name: "m1",
                Age:10,
        }
        b, _ := json.Marshal(u)
        fmt.Println(string(b))
}

//{"name":"m1","age":10}


//例子2:
type user struct {
        Name string `json:"name"`
        Age int `json:"age,omitempty"`
}

func main() {
        u := user{
                Name: "m1",
                Age:0,
        }
        b, _ := json.Marshal(u)
        fmt.Println(string(b))
}

//{"name":"m1"}


//例子3:
type user struct {
        Name string `json:"name"`
        Age int `json:"age,omitempty"`
}

func main() {
        u := user{
                Name: "m1",
        }
        b, _ := json.Marshal(u)
        fmt.Println(string(b))
}

//{"name":"m1"}


</code></pre>
<pre><code>- 删除字段:

//例子1:
type user struct {
        Name string `json:"name"`
        Ageint    `json:"-"`
}

func main() {
        u := user{
                Name: "m1",
                Age:12,
        }
        b, _ := json.Marshal(u)
        fmt.Println(string(b))
}

//{"name":"m1"}


//例子2:

type user struct {
        Name string `json:"name"`
        Ageint    `json:"-"`
}

func main() {
        u := user{
                Name: "m1",
                Age:0,
        }
        b, _ := json.Marshal(u)
        fmt.Println(string(b))
}

//{"name":"m1"}

</code></pre>
<pre><code>- json tag: string

// 例1:
type user struct {
        Name string `json:"name"`
        Ageint    `json:",string"`
}

func main() {
        u := user{
                Name: "m1",
                Age:22,
        }
        b, _ := json.Marshal(u)

        fmt.Println(string(b))
}

//{"name":"m1","Age":"22"}


// 例2:
type user struct {
        Name string `json:"name",int"` //str转int, 出错,但不报错
        Ageint
}

func main() {
        u := user{
                Name: "m1",
                Age:22,
        }
        b, err := json.Marshal(u)
        if err != nil {
                fmt.Println(err)
        }
        fmt.Println(string(b))
}

//{"name":"m1","Age":"22"}

</code></pre>
<ul>
<li>转go数据结构</li>
</ul>
<pre><code>- json类型和struct不匹配: 转换失败, 报错(支持类型校验)

type user struct {
        Name string `json:"name"`
        Ageint    `json:"age"`
}

func main() {
        var jsonStr = `
                {
                        "name":"m1",
                        "age":"22"
                }
        `
        var u user

        err := json.Unmarshal([]byte(jsonStr), &amp;u)
        if err != nil {
                fmt.Println(err)
        }
        fmt.Println(u)
}

//json: cannot unmarshal string into Go struct field user.age of type int
//{m1 0}
</code></pre>
<pre><code>- 支持类型转换(但不支持自适应)
type user struct {
    Name string `json:"name"`
    Ageint    `json:"age,string"`
}

func main() {
    var jsonStr = `
      {
            "name":"m1",
            "age":"22"
      }
    `
    var u user

    err := json.Unmarshal([]byte(jsonStr), &amp;u)
    if err != nil {
      fmt.Println(err.Error())
    }
    fmt.Printf("%#v",u)
}
//main.user{Name:"m1", Age:22}
</code></pre>
<pre><code>- 不支持弱类型转换
type user struct {
    Name string `json:"name"`
    Ageint    `json:"age,string"`
}

func main() {
    var jsonStr = `
      {
            "name":"m1",
            "age":22
      }
    `
    var u user

    err := json.Unmarshal([]byte(jsonStr), &amp;u)
    if err != nil {
      fmt.Println(err.Error())
    }
    fmt.Printf("%#v",u)
}
//json: invalid use of ,string struct tag, trying to unmarshal unquoted value into
// int
//main.user{Name:"m1", Age:0}
</code></pre>
<pre><code>- 如果json缺字段, struct以零值填充

type user struct {
        Name string `json:"name"`
        Ageint    `json:"age"`
}

func main() {
        var jsonStr = `
                {
                        "name":"m1"
                }
        `
        var u user

        err := json.Unmarshal([]byte(jsonStr), &amp;u)
        if err != nil {
                fmt.Println(err)
        }
        fmt.Println(u)
}

//{m1 0}
</code></pre>
<pre><code>- 无论多少层的json 都能Unmarshal到 mapinterface{}中
const jsonStr = `
                                {
                                        "name":{
                                                "first":"Janet",
                                                "last":"Prichard",
                                                "address":{"age":22}
                                        },
                                        "age":47
                                }
                                `

func main() {
        m := mapinterface{}{}

        json.Unmarshal([]byte(jsonStr), &amp;m)

        fmt.Printf("%#v", m)
}
//mapinterface {}{"age":47, "name":mapinterface {}{"address":mapinterface {}{"age":22}, "first":"Janet", "last":"Prichard"}}

</code></pre>
<ul>
<li>go JSON技巧</li>
</ul>
<pre><code>临时忽略struct空字段
临时添加额外的字段
临时粘合两个struct
一个json切分成两个struct
临时改名struct的字段
用字符串传递数字
容忍字符串和数字互转
容忍空数组作为对象
使用 MarshalJSON支持time.Time
使用 RegisterTypeEncoder支持time.Time
使用 MarshalText支持非字符串作为key的map
使用 json.RawMessage
使用 json.Number
统一更改字段的命名风格
使用私有的字段
忽略掉一些字段
忽略掉一些字段2
</code></pre>
<ul>
<li>json快速生成struct工具: json-to-go</li>
</ul>
<pre><code>- 练习: 写出下列json的struct:
{
    "resultcode": "200",
    "reason": "Return Successd!",
    "result": {
      "province": "浙江",
      "city": "杭州",
      "areacode": "0571",
      "zip": "310000",
      "company": "中国移动",
      "card": ""
    }
}



type Province struct {
        Resultcode string `json:"resultcode"`
        Reason   string `json:"reason"`
        Results    Results `json:"results"`
}

type Results struct {
        Province string `json:"province"`
        City   string `json:"city"`
        Areacode string `json:"areacode"`
        Zip      string `json:"zip"`
        Companystring `json:"company"`
        Card   string `json:"card"`
}
</code></pre>
<ul>
<li>友好的处理restful-api不定参数git: mapstructure</li>
</ul>
<pre><code>- 支持tag
func main() {
        // Note that the mapstructure tags defined in the struct type
        // can indicate which fields the values are mapped to.
        type Person struct {
                Name string `mapstructure:"person_name"`
                Ageint    `mapstructure:"person_age"`
        }

        input := mapinterface{}{
                "person_name": "Mitchell",
                "person_age":91,
        }

        var result Person
        err := Decode(input, &amp;result)
        if err != nil {
                panic(err)
        }

        fmt.Printf("%#v", result)
       
        //Output:
        //
        //mapstructure.Person{Name:"Mitchell", Age:91}
}
</code></pre>
<pre><code>- 支持字段类型校验
func main() {
        type Person struct {
                Name   string
                Age    int
                Emails []string
                Extramapstring
        }

        // This input can come from anywhere, but typically comes from
        // something like decoding JSON where we're not quite sure of the
        // struct initially.
        input := mapinterface{}{
                "name":   123,
                "age":    "bad value",
                "emails": []int{1, 2, 3},
        }

        var result Person
        err := Decode(input, &amp;result)
        if err == nil {
                panic("should have an error")
        }

        fmt.Println(err.Error())
       
        //Output:
        //
        //5 error(s) decoding:
        //* 'Age' expected type 'int', got unconvertible type 'string'
        //* 'Emails' expected type 'string', got unconvertible type 'int'
        //* 'Emails' expected type 'string', got unconvertible type 'int'
        //* 'Emails' expected type 'string', got unconvertible type 'int'
        //* 'Name' expected type 'string', got unconvertible type 'int'
}
</code></pre>
<pre><code>- 支持结构体嵌套
func main() {
        // Squashing multiple embedded structs is allowed using the squash tag.
        // This is demonstrated by creating a composite struct of multiple types
        // and decoding into it. In this case, a person can carry with it both
        // a Family and a Location, as well as their own FirstName.
        type Family struct {
                LastName string
        }
        type Location struct {
                City string
        }
        type Person struct {
                Family    `mapstructure:",squash"`
                Location`mapstructure:",squash"`
                FirstName string
        }

        input := mapinterface{}{
                "FirstName": "Mitchell",
                "LastName":"Hashimoto",
                "City":      "San Francisco",
        }

        var result Person
        err := Decode(input, &amp;result)
        if err != nil {
                panic(err)
        }

        fmt.Printf("%s %s, %s", result.FirstName, result.LastName, result.City)
       
        //Output:
        //
        //Mitchell Hashimoto, San Francisco
}
</code></pre>
<pre><code>- 支持类型自适应(week转换)
</code></pre>
<pre><code>- 实际的用处

// json数据: data对应结构体可能不同, 所以定义为 []mapstring

{
    "type": "UPDATE",
    "database": "blog",
    "table": "blog",
    "data": [
      {
            "blogId": "100001",
            "title": "title",
            "content": "this is a blog",
            "uid": "1000012",
            "state": "1"
      }
    ]
}



package main

import (
        "encoding/json"
        "fmt"
        "github.com/mitchellh/mapstructure"
)

type Event struct {
        Type   string            `json:"type"`
        Database string            `json:"database"`
        Table    string            `json:"table"`
        Data   []mapstring `json:"data"`
}

type Blog struct {
        BlogIdstring `mapstructure:"blogId"`
        Title   string `mapstructrue:"title"`
        Content string `mapstructure:"content"`
        Uid   int32`mapstructure:"uid"`
        State   int32`mapstructure:"state"`
}

func main() {
        msg := []byte(`{
    "type": "UPDATE",
    "database": "blog",
    "table": "blog",
    "data": [
      {
            "blogId": "100001",
            "title": "title",
            "content": "this is a blog",
            "uid": "1000012",
            "state": "1"
      }
    ]}`)
        e := Event{}
        if err := json.Unmarshal(msg, &amp;e); err != nil {
                panic(err)
        }
        if e.Table == "blog" {
                var blogs []Blog
                if err := mapstructure.WeakDecode(e.Data, &amp;blogs); err != nil {
                        panic(err)
                }

                fmt.Println(blogs)
        }
}
</code></pre>
<p>参考: GO小知识之实例演示 json 如何转化为 map 和 struct</p>
<pre><code>1. json.Unmarshal 将JSON转为 mapinterface{}。
        缺陷:
                需要检查key是否存在
                key 容易写错

2. 改进: 将不固定的部分即: Data: []mapstring
               固定的部分保持

3. 将可变字段用mapstructure转换为struct, 能自适应value类型

</code></pre>
<ul>
<li>gjson: 优雅的供json串直接取值</li>
</ul>
<pre><code>- 取值
package main

import "github.com/tidwall/gjson"

const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`

func main() {
        value := gjson.Get(json, "name.last")
        println(value.String())
}
</code></pre>
<pre><code>- 遍历
const json = `
                                {
                                        "name":{
                                                "first":"Janet",
                                                "last":"Prichard",
                                                "address":{"age":22}
                                        },
                                        "age":47
                                }
                                `
func main() {
        result := gjson.Get(json, "name")
        result.ForEach(func(key, value gjson.Result) bool {
                println(value.String())
                return true // keep iterating
        })
}
</code></pre>
<pre><code>- Unmarshal to a map

m, ok := gjson.Parse(json).Value().(mapinterface{})
if !ok {
        // not a map
}
</code></pre><br><br>
来源:https://www.cnblogs.com/iiiiiher/p/12118352.html
頁: [1]
查看完整版本: [go]灵活的处理json与go结构体