JSON处理

JSON是一种轻量级的数据交换语言。

1. 解析JSON[Unmarshal(data []byte, v interface{})]

1.1. Unmarshal源码

/src/encoding/json/decode.go

  1. func Unmarshal(data []byte, v interface{}) error {
  2. // Check for well-formedness.
  3. // Avoids filling out half a data structure
  4. // before discovering a JSON syntax error.
  5. var d decodeState
  6. err := checkValid(data, &d.scan)
  7. if err != nil {
  8. return err
  9. }
  10. d.init(data)
  11. return d.unmarshal(v)
  12. }
  13. ...
  14. func (d *decodeState) unmarshal(v interface{}) (err error) {
  15. defer func() {
  16. if r := recover(); r != nil {
  17. if _, ok := r.(runtime.Error); ok {
  18. panic(r)
  19. }
  20. err = r.(error)
  21. }
  22. }()
  23. rv := reflect.ValueOf(v)
  24. if rv.Kind() != reflect.Ptr || rv.IsNil() {
  25. return &InvalidUnmarshalError{reflect.TypeOf(v)}
  26. }
  27. d.scan.reset()
  28. // We decode rv not rv.Elem because the Unmarshaler interface
  29. // test must be applied at the top level of the value.
  30. d.value(rv)
  31. return d.savedError
  32. }

1.2. 解析到结构体

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. type Server struct {
  7. ServerName string
  8. ServerIP string
  9. }
  10. type Serverslice struct {
  11. Servers []Server
  12. }
  13. func main() {
  14. var s Serverslice
  15. str := `{"servers":
  16. [{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},
  17. {"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]}`
  18. err:=json.Unmarshal([]byte(str), &s)
  19. if err!=nil{
  20. fmt.Println(err)
  21. }
  22. fmt.Println(s)
  23. }

说明

JSON格式与结构体一一对应,Unmarshal方法即将JSON文本转换成结构体。只会匹配结构体中的可导出字段,即首字母大写字段(类似java的public),匹配规则如下:json的key为Foo为例

  1. 先查找struct tag中含有Foo的可导出的struct字段(首字母大写)
  2. 其次查找字段名为Foo的可导出字段。
  3. 最后查找类似FOO或者FoO这类除首字母外,其他大小写不敏感的可导出字段。

1.3. 解析到interface

2. 生成JSON[Marshal(v interface{})]

2.1. Marshal源码

/src/encoding/json/encode.go

  1. func Marshal(v interface{}) ([]byte, error) {
  2. e := &encodeState{}
  3. err := e.marshal(v)
  4. if err != nil {
  5. return nil, err
  6. }
  7. return e.Bytes(), nil
  8. }
  9. ...
  10. func (e *encodeState) marshal(v interface{}) (err error) {
  11. defer func() {
  12. if r := recover(); r != nil {
  13. if _, ok := r.(runtime.Error); ok {
  14. panic(r)
  15. }
  16. if s, ok := r.(string); ok {
  17. panic(s)
  18. }
  19. err = r.(error)
  20. }
  21. }()
  22. e.reflectValue(reflect.ValueOf(v))
  23. return nil
  24. }

2.2. 使用方法

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. type Server struct {
  7. ServerName string `json:"serverName,string"`
  8. ServerIP string `json:"serverIP,omitempty"`
  9. }
  10. type Serverslice struct {
  11. Servers []Server `json:"servers"`
  12. }
  13. func main() {
  14. var s Serverslice
  15. s.Servers = append(s.Servers, Server{ServerName: "Shanghai_VPN", ServerIP: "127.0.0.1"})
  16. s.Servers = append(s.Servers, Server{ServerName: "Beijing_VPN", ServerIP: "127.0.02"})
  17. b, err := json.Marshal(s)
  18. if err != nil {
  19. fmt.Println("JSON ERR:", err)
  20. }
  21. fmt.Println(string(b))
  22. }

2.3. 说明

Marshal方法将结构体转换成json文本,匹配规则如下:

  1. 如果字段的tag是“-”,那么该字段不会输出到JSON。
  2. 如果tag中带有自定义名称,那么该自定义名称会出现在JSON字段名中。例如例子中的“serverName”
  3. 如果tag中带有“omitempty”选项,那么如果该字段值为空,就不会输出到JSON中。
  4. 如果字段类型是bool,string,int,int64等,而tag中带有“,string”选项,那么这个字段在输出到JSON的时候会把该字段对应的值转换成JSON字符串。

注意事项:

  1. Marshal只有在转换成功的时候才会返回数据,JSON对象只支持string作为key,如果要编码一个map,那么必须是map[string]T这种类型。(T为任意类型)
  2. Channel,complex和function不能被编码成JSON。
  3. 嵌套的数据不能编码,会进入死循环。
  4. 指针在编码时会输出指针指向的内容,而空指针会输出null。