GO JSON处理
初次接触go的json处理方式,在此记录,以便后续查阅。
内心os:对比python,go处理json的方式真是复杂许多
1. 解析已知结构的json
针对已知结构的json,编码和解码比较方便,使用标准库encoding/json的Marshal和Unmarshal方法即可,比较麻烦的就是定义结构体
我们定义一个json数据
{
"name": "张三",
"sex": "男",
"age": 18,
"relasionships": [
{
"name": "张二",
"relasionship": "父亲"
},
{
"name": "李二",
"relasionship": "母亲"
}
]
}
首先定义对应的go结构体
type Person struct {
Name string `json:"name"` //加入标签给字段的json格式命名
Sex string `json:"sex"`
Age int `json:"age"`
Relasionships []struct {
Name string `json:"name"`
Relasionship string `json:"relasionship"`
} `json:"relasionships"`
}
json.Marshal()函数定义
func Marshal(v any) ([]byte, error) {
e := newEncodeState()
err := e.marshal(v, encOpts{escapeHTML: true})
if err != nil {
return nil, err
}
buf := append([]byte(nil), e.Bytes()...)
encodeStatePool.Put(e)
return buf, nil
}
基于此结构体解析json数据
func MarshalJson() {
p := Person{
Name: "张三",
Sex: "男",
Age: 18,
Relasionships: []struct {
Name string `json:"name"`
Relasionship string `json:"relasionship"`
}{{"张二", "父亲"}, {"李二", "母亲"}},
}
data, err := json.Marshal(&p)
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(string(data))
}
最终输出如下
{"name":"张三","sex":"男","age":18,"relasionships":[{"name":"张二","relasionship":"父亲"},{"name":"李二","relasionship":"母亲"}]}
我们给结构体加上对应的json标签,使其输出的效果和我们的预期一致。
解码则使用json.Unmarshal()
函数定义
func Unmarshal(data []byte, v any) error {
// Check for well-formedness.
// Avoids filling out half a data structure
// before discovering a JSON syntax error.
var d decodeState
err := checkValid(data, &d.scan)
if err != nil {
return err
}
d.init(data)
return d.unmarshal(v)
}
解码代码
func UnmarshalJson() {
data := []byte(`{"name":"张三","sex":"男","age":18,"relasionships":[{"name":"张二","relasionship":"父亲"},{"name":"李二","relasionship":"母亲"}]}`)
p := Person{}
json.Unmarshal(data, &p)
fmt.Printf("name: %s, sex: %s, age: %d\n", p.Name, p.Sex, p.Age)
for _, r := range p.Relasionships {
fmt.Printf("name: %s, relasionship: %s\n", r.Name, r.Relasionship)
}
}
输出结果如下:
name: 张三, sex: 男, age: 18
name: 张二, relasionship: 父亲
name: 李二, relasionship: 母亲
当json字符串中出现了结构体未定义的字段,go不会将其解析到结构体中。
而结构体字段不存在时,结构体会赋予该字段类型的零值
输入 : {"name":"张三","identify":"123456","age":18,"relasionships":[{"name":"张二","relasionship":"父亲"},{"name":"李二","relasionship":"母亲"}]}
输出为:
name: 张三, sex: , age: 18
name: 张二, relasionship: 父亲
name: 李二, relasionship: 母亲
2. 解析未知结构的json
当我们不知道接收到的json结构,我们需要用到空接口类型 interface{}
我们继续用上述json做实验,因类型均未确定,所以遍历取值时需要判断类型
JSON数据里面的元素类型将做如下转换:
·JSON中的布尔值将会转换为Go中的bool类型;
·数值会被转换为Go中的float64类型;
·字符串转换后还是string类型;
·JSON数组会转换为[]interface{}类型;
·JSON对象会转换为map[string]interface{}类型;
·null值会被转换为nil.
func UnknownJson() {
data := []byte(`{"name":"张三","identify":"123456","age":18,"relasionships":[{"name":"张二","relasionship":"父亲"},{"name":"李二","relasionship":"母亲"}]}`)
var p interface{}
json.Unmarshal(data, &p)
for k, v := range p.(map[string]interface{}) {
switch value := v.(type) {
case string:
fmt.Printf("%s: %s string\n", k, value)
case float64:
fmt.Printf("%s: %f float64\n", k, value)
case bool:
fmt.Printf("%s: %t bool\n", k, value)
case []interface{}:
fmt.Println(value)
}
}
}
输出结果为:
name: 张三 string
identify: 123456 string
age: 18.000000 float64
[map[name:张二 relasionship:父亲] map[name:李二 relasionship:母亲]]
可以感觉到,未知类型的遍历十分麻烦