结构体的数据是{"user_id": 344, "user_name": "shiki"}

下面给出的user_id是int,json使用string类型去接数据会报错。

1
2
3
4
5
6
type User struct {
Id string `json:"user_id,int"`
Username string `json:"user_name"`
}

// json: cannot unmarshal number into Go value of type string

json.Number

使用json.Number解决。

1
2
3
4
type User struct {
Id json.Number `json:"user_id"`
Username string `json:"user_name"`
}
  • marshal函数出来的数据依然会是int类型,而不是字符串。

json.RawMessage

这个类型,表示json不会去往下解析数据了,其数据还是裸json数据。

官方解释

1
RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding.

这还不算,按照文档后一句,can be used to delay JSON decoding or precompute a JSON encoding.,能延迟处理json数据,或者是预处理json数据,这里是不是有很多好玩的了。

延迟处理

在json数据比较大,且具有相当的层级的时候,我可能只需要先解析出一部分数据(能供我使用的数据),其他数据等需要的时候再一并解析。

当然,即使这里我不去解析那部分没有解析的json的数据,json库也是帮助我们预处理过了这部分数据的,也就是说其已经验证过这些数据是符合json规范的。

1
2
3
4
5
6
7
8
input := `{"user_id": "{"dsad":", "user_name": "shiki"}`
user := User{}
err := json.Unmarshal([]byte(input), &user)
if err != nil {
panic(err)
}

// panic: invalid character 'd' after object key:value pair

如果在pprof上,看到json处理占用了很多性能开销,业务场景上又恰巧可以使用到合乎这个场景,那么不妨试试用这个方法来提升json性能。

使用Jsoniter

看到有人推荐这个,然后去搜了下使用方式,发现非常简单易用,也是为这种需求新增了一种方案了。

此内容参考自: 用golang解析json里的数字栏位

1
import extra "github.com/json-iterator/go/extra"

函数加入:extra.RegisterFuzzyDecoders()

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

import (
"fmt"
jsoniter "github.com/json-iterator/go"
extra "github.com/json-iterator/go/extra"
)

type Sample struct {
Name string
Age int
}

const sampleData = `{
"name":"julian",
"age": 45
}`

const sampleData2 = `{
"name":"julian",
"age": "45"
}`

func main() {
extra.RegisterFuzzyDecoders()
var sample Sample
err := jsoniter.Unmarshal([]byte(sampleData), &sample)

if err != nil {
panic(err)
}
fmt.Println(sample)

err = jsoniter.Unmarshal([]byte(sampleData2), &sample)

if err != nil {
panic(err)
}
fmt.Println(sample)

}