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


    • go数据结构与json数据结构对应( json.Unmarshal帮助手册)
    
     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 nul
    
    
    注: 手册里可以看到转json时, 常见选项的含义和例子.
    
    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 := map[string]int{"apple": 5, "lettuce": 7}
        mapB, _ := json.Marshal(mapD)
        fmt.Println(string(mapB))
    
        res1D := &response1{
            Page:   1,
            Fruits: []string{"apple", "peach", "pear"}}
        res1B, _ := json.Marshal(res1D)
        fmt.Println(string(res1B))
    
        res2D := &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 map[string]interface{}
    
        if err := json.Unmarshal(byt, &dat); err != nil {
            panic(err)
        }
        fmt.Println(dat)
    
        num := dat["num"].(float64)
        fmt.Println(num)
    
        strs := dat["strs"].([]interface{})
        str1 := strs[0].(string)
        fmt.Println(str1)
    
        str := `{"page": 1, "fruits": ["apple", "peach"]}`
        res := response2{}
        json.Unmarshal([]byte(str), &res)
        fmt.Println(res)
        fmt.Println(res.Fruits[0])
        
        //上面unmarshal得到的都是字节数组,  这里直接将字节数组写入流
        enc := json.NewEncoder(os.Stdout)
        d := map[string]int{"apple": 5, "lettuce": 7}
        enc.Encode(d)
    }
    
    • go数据类型转json: struct tag for json: 结构体转json时作用
    
    /*
    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:"-,"
    */
    
    - 默认
    type user struct {
    	Name string
    	Age  int
    }
    
    func main() {
    	u := user{
    		Name: "m1",
    		Age:  22,
    	}
    	b, _ := json.Marshal(u)
    	fmt.Println(string(b))
    }
    // {"Name":"m1","Age":22}
    
    
    - json tag: 
    
    type user struct {
    	Name string `json:"name"`
    	Age  int    `json:"age"`
    }
    
    func main() {
    	u := user{
    		Name: "m1",
    		Age:  22,
    	}
    	b, _ := json.Marshal(u)
    	fmt.Println(string(b))
    }
    
    // {"name":"m1","age":22}
    
    - struct实例缺少字段
    
    type user struct {
    	Name string `json:"name"`
    	Age  int    `json:"age"`
    }
    
    func main() {
    	u := user{
    		Name: "m1",
    	}
    	b, _ := json.Marshal(u)
    	fmt.Println(string(b))
    }
    
    // {"name":"m1","age":0}
    
    - 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"}
    
    
    
    - 删除字段:
    
    //例子1:
    type user struct {
    	Name string `json:"name"`
    	Age  int    `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"`
    	Age  int    `json:"-"`
    }
    
    func main() {
    	u := user{
    		Name: "m1",
    		Age:  0,
    	}
    	b, _ := json.Marshal(u)
    	fmt.Println(string(b))
    }
    
    //{"name":"m1"}
    
    
    - json tag: string
    
    // 例1:
    type user struct {
    	Name string `json:"name"`
    	Age  int    `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, 出错,但不报错
    	Age  int 
    }
    
    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"}
    
    
    • 转go数据结构
    - json类型和struct不匹配: 转换失败, 报错(支持类型校验)
    
    type user struct {
    	Name string `json:"name"`
    	Age  int    `json:"age"`
    }
    
    func main() {
    	var jsonStr = `
    		{
    			"name":"m1",
    			"age":"22"
    		}
    	`
    	var u user
    
    	err := json.Unmarshal([]byte(jsonStr), &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}
    
    - 支持类型转换(但不支持自适应)
    type user struct {
        Name string `json:"name"`
        Age  int    `json:"age,string"`
    }
    
    func main() {
        var jsonStr = `
            {
                "name":"m1",
                "age":"22"
            }
        `
        var u user
    
        err := json.Unmarshal([]byte(jsonStr), &u)
        if err != nil {
            fmt.Println(err.Error())
        }
        fmt.Printf("%#v",u)
    }
    //main.user{Name:"m1", Age:22}
    
    - 不支持弱类型转换
    type user struct {
        Name string `json:"name"`
        Age  int    `json:"age,string"`
    }
    
    func main() {
        var jsonStr = `
            {
                "name":"m1",
                "age":22
            }
        `
        var u user
    
        err := json.Unmarshal([]byte(jsonStr), &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}
    
    - 如果json缺字段, struct以零值填充
    
    type user struct {
    	Name string `json:"name"`
    	Age  int    `json:"age"`
    }
    
    func main() {
    	var jsonStr = `
    		{
    			"name":"m1"
    		}
    	`
    	var u user
    
    	err := json.Unmarshal([]byte(jsonStr), &u)
    	if err != nil {
    		fmt.Println(err)
    	}
    	fmt.Println(u)
    }
    
    //{m1 0}
    
    - 无论多少层的json 都能Unmarshal到 map[string]interface{}中
    const jsonStr = `
    				{
    					"name":{
    						"first":"Janet",
    						"last":"Prichard",
    						"address":{"age":22}
    					},
    					"age":47
    				}
    				`
    
    func main() {
    	m := map[string]interface{}{}
    
    	json.Unmarshal([]byte(jsonStr), &m)
    
    	fmt.Printf("%#v", m)
    }
    //map[string]interface {}{"age":47, "name":map[string]interface {}{"address":map[string]interface {}{"age":22}, "first":"Janet", "last":"Prichard"}}
    
    
    临时忽略struct空字段
    临时添加额外的字段
    临时粘合两个struct
    一个json切分成两个struct
    临时改名struct的字段
    用字符串传递数字
    容忍字符串和数字互转
    容忍空数组作为对象
    使用 MarshalJSON支持time.Time
    使用 RegisterTypeEncoder支持time.Time
    使用 MarshalText支持非字符串作为key的map
    使用 json.RawMessage
    使用 json.Number
    统一更改字段的命名风格
    使用私有的字段
    忽略掉一些字段
    忽略掉一些字段2
    
    - 练习: 写出下列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"`
    	Company  string `json:"company"`
    	Card     string `json:"card"`
    }
    
    - 支持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"`
    		Age  int    `mapstructure:"person_age"`
    	}
    
    	input := map[string]interface{}{
    		"person_name": "Mitchell",
    		"person_age":  91,
    	}
    
    	var result Person
    	err := Decode(input, &result)
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Printf("%#v", result)
    	
    	//Output:
    	//
    	//mapstructure.Person{Name:"Mitchell", Age:91}
    }
    
    - 支持字段类型校验
    func main() {
    	type Person struct {
    		Name   string
    		Age    int
    		Emails []string
    		Extra  map[string]string
    	}
    
    	// 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 := map[string]interface{}{
    		"name":   123,
    		"age":    "bad value",
    		"emails": []int{1, 2, 3},
    	}
    
    	var result Person
    	err := Decode(input, &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[0]' expected type 'string', got unconvertible type 'int'
    	//* 'Emails[1]' expected type 'string', got unconvertible type 'int'
    	//* 'Emails[2]' expected type 'string', got unconvertible type 'int'
    	//* 'Name' expected type 'string', got unconvertible type 'int'
    }
    
    - 支持结构体嵌套
    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 := map[string]interface{}{
    		"FirstName": "Mitchell",
    		"LastName":  "Hashimoto",
    		"City":      "San Francisco",
    	}
    
    	var result Person
    	err := Decode(input, &result)
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Printf("%s %s, %s", result.FirstName, result.LastName, result.City)
    	
    	//Output:
    	//
    	//Mitchell Hashimoto, San Francisco
    }
    
    - 支持类型自适应(week转换)
    
    - 实际的用处
    
    // json数据: data对应结构体可能不同, 所以定义为 []map[string]string
    
    {
        "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     []map[string]string `json:"data"`
    }
    
    type Blog struct {
    	BlogId  string `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, &e); err != nil {
    		panic(err)
    	}
    	if e.Table == "blog" {
    		var blogs []Blog
    		if err := mapstructure.WeakDecode(e.Data, &blogs); err != nil {
    			panic(err)
    		}
    
    		fmt.Println(blogs)
    	}
    }
    

    参考: GO小知识之实例演示 json 如何转化为 map 和 struct

    1. json.Unmarshal 将JSON转为 map[string]interface{}。
    	缺陷:
    		需要检查key是否存在
    		key 容易写错
    
    2. 改进: 将不固定的部分即: Data: []map[string]string
    		 固定的部分保持
    
    3. 将可变字段用mapstructure转换为struct, 能自适应value类型
    
    
    - 取值
    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())
    }
    
    - 遍历
    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
    	})
    }
    
    - Unmarshal to a map
    
    m, ok := gjson.Parse(json).Value().(map[string]interface{})
    if !ok {
    	// not a map
    }
    
  • 相关阅读:
    一个故事讲透供应链的三大战略
    电商系统之订单正向与逆向流程设计
    广告深度预估技术在美团到店场景下的突破与畅想
    美团智能客服核心技术与实践
    供应链里的批次管理,你了解多少
    对于HTML语义化的理解
    前端三大框架中Vue与React区别
    对于mvc模式的理解与学习
    对于javascript里面闭包的理解
    webpack的理解与使用
  • 原文地址:https://www.cnblogs.com/iiiiiher/p/12118352.html
Copyright © 2020-2023  润新知