Go-json源码解析
代码例子如下:
type Student struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
stu := Student{
Name: "张三",
Age: 21,
}
buf := bytes.NewBuffer(make([]byte, 0)) // 新建一个缓冲区,用于存放编码过的内容
enc := json.NewEncoder(buf) // 实例化一个编码器
if err := enc.Encode(&stu); err != nil { // 编码 Student 结构体
log.Fatal(err)
}
p, _ := ioutil.ReadAll(buf) // 实际上为 io.ReadAll(r)
fmt.Println(string(p)) // 输出缓冲区内容
buf.Reset() // 将缓冲区清空
buf.Write(p) // 写入json数据
dec := json.NewDecoder(buf) // 实例化一个解码器
var stu2 Student = Student{}
if err := dec.Decode(&stu2); err != nil { // 开始解码
log.Fatal(err)
}
fmt.Println(stu2)
}
这里我们可以发现,编码过程与解码过程极其相似,故我们拿编码进行讨论(解码相似,就不再过多重复讨论)。显而易见的是,json.NewEncoder(buf)
该函数是实例化一个编码器,其中代码也极其简单: return &Encoder{w: w, escapeHTML: true}//返回一个Encoder结构体
接下来我们将要讨论enc.Encode(&stu)
这个编码函数,首先我们来看一下Encoder的结构:
// An Encoder writes JSON values to an output stream.
type Encoder struct {
w io.Writer // 编码结果
err error // 错误集
escapeHTML bool // escapeHTML将< > & " '转成字符实体
indentBuf *bytes.Buffer // 内置buf
indentPrefix string // 前缀
indentValue string // 前缀后值,一般为'\t'缩进
}
接下来我们来看看Encode这个函数的流程:
func (enc *Encoder) Encode(v any) error {
if enc.err != nil { // 判断编码器是否存在错误
return enc.err
}
e := newEncodeState() // 创建一个 状态器,这里采用sync.Pool来实现
err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML}) // 进行解析json
if err != nil {
return err
}
e.WriteByte('\n') // 末尾换行 执行体的是内置缓冲区
b := e.Bytes() // 将内置buffer赋值于b
if enc.indentPrefix != "" || enc.indentValue != "" { // 如果前缀及值存在
if enc.indentBuf == nil { // 如果内置缓冲区为空,则实例化一个缓冲区
enc.indentBuf = new(bytes.Buffer)
}
enc.indentBuf.Reset() // 重置缓冲区
err = Indent(enc.indentBuf, b, enc.indentPrefix, enc.indentValue) // 调整json格式的缩进
if err != nil {
return err
}
b = enc.indentBuf.Bytes() // 重新取出enc内置缓冲区
}
if _, err = enc.w.Write(b); err != nil { // 将结果写入缓冲区
enc.err = err
}
encodeStatePool.Put(e) // 将 状态器 交还给状态池
return err
}
同样的,在json之中存在着json.Marshal(&stu)
函数与上述函数完成功能相同,并且更加简便,其中的流程其实与上述没有太大区别(不过该解析函数之中没有了Indent
处理缩进了)
func Marshal(v any) ([]byte, error) {
e := newEncodeState() // 实例化一个 状态器
err := e.marshal(v, encOpts{escapeHTML: true}) // 解析数据到json,关键函数
if err != nil {
return nil, err
}
buf := append([]byte(nil), e.Bytes()...)
encodeStatePool.Put(e) // 归还 状态器
return buf, nil
}
我们跟入到marshal
函数:(最外层实际上仅仅是捕捉异常,进入的函数是e.reflectValue(reflect.ValueOf(v), opts)
func (e *encodeState) marshal(v any, opts encOpts) (err error) {
defer func() { // 捕获异常
if r := recover(); r != nil {
if je, ok := r.(jsonError); ok {
err = je.error
} else {
panic(r)
}
}
}()
e.reflectValue(reflect.ValueOf(v), opts)
return nil
}
继续跟进查看:
func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) {
valueEncoder(v)(e, v, opts) // valueEncoder(v)返回一个函数指针,并执行f(e, v, opts)
}
func valueEncoder(v reflect.Value) encoderFunc { // 跟入查看返回值encoderFunc
if !v.IsValid() {
return invalidValueEncoder
}
return typeEncoder(v.Type()) // 关键函数typeEncoder(v.Type())
}
var encoderCache sync.Map // map[reflect.Type]encoderFunc
func typeEncoder(t reflect.Type) encoderFunc { // 利用sync.Map来实现查找对应的encode
if fi, ok := encoderCache.Load(t); ok { // 如果存在直接返回
return fi.(encoderFunc)
}
// To deal with recursive types, populate the map with an
// indirect func before we build it. This type waits on the
// real func (f) to be ready and then calls it. This indirect
// func is only used for recursive types.
var (
wg sync.WaitGroup
f encoderFunc
)
wg.Add(1)
fi, loaded := encoderCache.LoadOrStore(t, encoderFunc(func(e *encodeState, v reflect.Value, opts encOpts) { // 进行储存到sync.Map之中
wg.Wait()
f(e, v, opts)
}))
if loaded {
return fi.(encoderFunc)
}
// Compute the real encoder and replace the indirect func with it.
f = newTypeEncoder(t, true) // 关键函数,返回encoderFunc,实际上实现
wg.Done()
encoderCache.Store(t, f)
return f
}
我们进行跟踪后发现实际上的关键函数为newTypeEncoder(t, true)
,同时该函数返回的函数指针如下(大体相同,根据不同的输入返回不同的处理函数)
func (pe ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
if v.IsNil() {
e.WriteString("null")
return
}
if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter {
// We're a large number of nested ptrEncoder.encode calls deep;
// start checking if we've run into a pointer cycle.
ptr := v.Interface()
if _, ok := e.ptrSeen[ptr]; ok {
e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())})
}
e.ptrSeen[ptr] = struct{}{}
defer delete(e.ptrSeen, ptr)
}
pe.elemEnc(e, v.Elem(), opts) // 解析json数据
e.ptrLevel--
}
而该函数实际上也是一层封装,具体执行函数体是pe.elemEnc(e, v.Elem(), opts)
,经过具体调试,发现最终处理函数为:
func (se structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
next := byte('{')
FieldLoop:
for i := range se.fields.list {
f := &se.fields.list[i]
// Find the nested struct field by following f.index.
fv := v
for _, i := range f.index {
if fv.Kind() == reflect.Pointer {
if fv.IsNil() {
continue FieldLoop
}
fv = fv.Elem()
}
fv = fv.Field(i)
}
if f.omitEmpty && isEmptyValue(fv) {
continue
}
e.WriteByte(next)
next = ','
if opts.escapeHTML {
e.WriteString(f.nameEscHTML)
} else {
e.WriteString(f.nameNonEsc)
}
opts.quoted = f.quoted
f.encoder(e, fv, opts)
}
if next == '{' {
e.WriteString("{}")
} else {
e.WriteByte('}')
}
}
最终,我来解释一下这么长的流程吧: json.Marshal(&stu) --> e.marshal(v, encOpts{escapeHTML: true}) --> e.reflectValue(reflect.ValueOf(v), opts) --> valueEncoder(v)(e, v, opts) --> typeEncoder(v.Type()) --> newTypeEncoder(t, true) --> newPtrEncoder(t) --> ptrEncoder{typeEncoder(t.Elem())} --> newStructEncoder(t) --> func (se structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts);可以看出来,层层封装,不过其中的newTypeEncoder(t, true)
起到了一个中转作用,首先返回了ptrEncoder{typeEncoder(t.Elem())}
结构体,但其中结构体的t.Elem()重新调用了newTypeEncoder函数,指向了newStructEncoder(t)所返回的处理函数;
对应的,我们来简单看一下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 // 与Encode相似,同样的一个 解码状态器
err := checkValid(data, &d.scan)
if err != nil {
return err
}
d.init(data) // 将data注册到decodeState之中的内置切片
return d.unmarshal(v) // 解析json数据
}