golang json

json 序列化/反序列化规则

bool  for JSON booleans
float64 for JSON numbers(包含 int,int64,int32,int16 ...)
string, for JSON strings (包含字符串,时间)
[]interface{}, for JSON arrays(数字,字符串,对象等组成的数组,json )
map[string]interface{}, for JSON objects 
nil for JSON null

golang 为什么要有jsontag

由于golang使用大小作为是否导出属性,方法的定义的规则。 造成golang json Unmarshal 无法将小写开头的json的key解析到struct结构。 例如:

a := `{"a":2}`
type aStruct struct {
    A int
    a int
}

json Unmarshal 后, A/a 字段中都是空值。 在给结构的key 加上tag后就可以取出 小写字段的key

a := `{"a":2,"aa":4}`
type aStruct struct {
    A int `json:"a"`
    a int `json:"aa"` //小写属性加tag是无意义的。值解析不上的
}

golang 内置tag

omitempty:如果字段的值为空
(boolean as false, number as 0,  nil pointer, a nil interface value, and any empty array, slice, map, or string)
在序列化时该字段不存
-:该字段在json 序列化/反序列忽律
string:将字段值在编码过程中转换成 JSON 中的字符串类型,只有当字段类型是 string, floating point, integer, or boolean 的情况下才会转换。

golang tag 作用

  1. 反序列化支持json小写key反写到struct 的key中
  2. 支持json中的key转化 ``` type Login struct { User string json:"usr" Password string json:"pwd" }

### golang json 反序列一个key支持多种数据类型

由于golang 是一种强类型语言。struct对象的key类型是固定的。
但是在弱类型语言中对就不一样了。 

例如:PHP (支持key为字符串)
如果 PHP array是空的时候,序列化出来是[]。
但是不为空的时候,序列化出来的是{"key":"value"}或者是["val1","val2"]
我们需要把 [] 当成 {} 处理。


这种情况我们可以使用重载UnmarshalJson的方法来实现

```golang 
代码:
package main

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

type AField struct {
	A map[string]interface{}
	B []string
}

func (a *AField) UnmarshalJSON(b []byte) error {
	str := strings.TrimSpace(string(b))
	if str == "" || str == "[]" {
		a.A = nil
		return nil
	}
	if err := json.Unmarshal(b, &a.B); err == nil {
		return nil
	}
	return json.Unmarshal(b, &a.A)
}

type tmpStruct struct {
	A AField `json:"a"`
}

func main() {
	strArr := `{"a":["b","b"]}`
	strMap := `{"a":{"aa":"11"}}`

	t1 := new(tmpStruct)
	t2 := new(tmpStruct)
	json.Unmarshal([]byte(strArr), t1)
	json.Unmarshal([]byte(strMap), t2)

	fmt.Println(fmt.Sprintf("%#v", t1))
	fmt.Println(fmt.Sprintf("%#v", t2))
}
结果:

&main.tmpStruct{A:main.AField{A:map[string]interface {}(nil), B:[]string{"b", "b"}}}
&main.tmpStruct{A:main.AField{A:map[string]interface {}{"aa":"11"}, B:[]string(nil)}}
articles from reage blog -- http://www.ireage.com