go语言json处理

258 阅读2分钟

这两天工作中遇到了很多json处理(一看就是写web的...),碰到了很多坑,所以把用法整理了一下放到这里做参考

Encode && Marshal

package main

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

type paramsStruct struct {
	Id    int    `json:"id"`
	Title string `json:"name"`
	Etc   etcStruct `json:"etc"`
}

type etcStruct struct {
	Content string `json:"content"`
}

func main() {

	params := paramsStruct{
		Id:    3,
		Title: "ha",
		Etc: etcStruct{Content: "content"},

	}
	paramsMap := map[string]interface{}{
		"Id":    1,
		"title": "ha",
		"etc": map[string]interface{}{
			"content": "content",
		},
	}
	a, _ := json.Marshal(params)
	fmt.Println(string(a))
	b, _ := json.Marshal(paramsMap)
	fmt.Println(string(b))

	var buf bytes.Buffer
	json.NewEncoder(&buf).Encode(params)
	fmt.Print(buf.String())
	var buf2 bytes.Buffer
	json.NewEncoder(&buf2).Encode(paramsMap)
	fmt.Print(buf2.String())
}

output

{"id":3,"name":"ha","etc":{"content":"content"}}
{"Id":1,"etc":{"content":"content"},"title":"ha"}
{"id":3,"name":"ha","etc":{"content":"content"}}
{"Id":1,"etc":{"content":"content"},"title":"ha"}

Decode && UnMarshal

package main

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

type paramsStruct struct {
	Id    int       `json:"id"`
	Title string    `json:"name"`
	Etc   etcStruct `json:"etc"`
}

type etcStruct struct {
	Content string `json:"content"`
}

func main() {
	var param paramsStruct
	var paramsMap map[string]interface{}
	jsonStr := `{"id":3,"name":"ha","etc":{"content":"content"}}`
	json.Unmarshal([]byte(jsonStr), &param)
	json.Unmarshal([]byte(jsonStr), &paramsMap)
	fmt.Println(param)
	fmt.Println(paramsMap)

	json.NewDecoder(strings.NewReader(jsonStr)).Decode(&param)
	json.NewDecoder(strings.NewReader(jsonStr)).Decode(&paramsMap)
	fmt.Println(param)
	fmt.Println(paramsMap)
}

output

{3 ha {content}}
map[etc:map[content:content] id:3 name:ha]
{3 ha {content}}
map[etc:map[content:content] id:3 name:ha]

总结

  1. 对struct的转换依赖于注解,如果没有依赖于字段名
  2. Marshal UnMarshal是对[]bype和(struct或者map[string]interface{})做相互转换
  3. NewEncode参数为io.Writer,bytes.Buffer实现了接口;newDecode参数为io.Reader,可以通过strings.NewReader()方法转换字符串为io.Reader
  4. Encode时struct 如果没有注解结果为空

其他

  1. struct 中多一个字段或json 中少一个字段不影响解析.
  2. 注解中加入omitempty时,encode忽略零值
  3. json 和struct类型不一致会忽略并报错.解决方法
    • json:"id,string"
    • 如下实现
package main

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

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func (p *Person) UnmarshalJSON(b []byte) error {
	var objMap map[string]*json.RawMessage
	err := json.Unmarshal(b, &objMap)
	if err != nil {
		return err
	}

	var name string
	err = json.Unmarshal(*objMap["name"], &name)
	if err != nil {
		return err
	}

	var ageInt int
	err = json.Unmarshal(*objMap["age"], &ageInt)
	if err != nil {
		// age  is string
		var ageString string
		err = json.Unmarshal(*objMap["age"], &ageString)
		if err != nil {
			return err
		}
		aI, err := strconv.Atoi(ageString)
		if err != nil {
			return err
		}
		p.Age = aI

	} else {
		p.Age = ageInt
	}

	p.Name = name

	fmt.Printf("%+v", *p)

	return nil
}

func main() {
	p := `{"name": "John", "age": "10"}`
	//	p := `{"name": "John", "age": 10}`


	newP := Person{}
	err := newP.UnmarshalJSON([]byte(p))
	if err != nil {
		fmt.Printf("Error %+v", err)
	}

}