decoder
入口函数:
1 | func Unmarshal(data []byte, v interface{}) error { |
golang 的 json decoder从Unmarshal进入,该函数创建一个decodeState结构体,该结构体用于存储解析json数据时当前的解析状态信息,例如下个需要解析的字符串的截止index,在解析中遇到的错误,以及一个存储了一个json解析的状态机。该函数首先会遍历一遍json字符串,用状态机来判断一个是否是一个合法的json字符串。如果是一个合法的字符串,则再变遍历变解析。所以一次decode操作会遍历两次json字符串。
状态机解析
首先看第一步用状态机判断是否是一个合法的json字符串是如何实现的。
状态机结构体的定义如下:
1 | // A scanner is a JSON scanning state machine. |
scanner的定义很简单,只有5个字段。第一个字段step,它是一个函数类型,注释的解释是它用于根据状体机当前的状态,以及输入的字符来前往下一个状态(即改变状态机结构体内部的数据),并返回一个int类型的code,用来告诉当前是否有一些事件发生,例如是字符串序列的结束字符(第二个引号)、对象类型的结束字符(”}”)、字符串的的结束字符(”]”)、解析出错等等。
第二个字段endTop,用于标记是否当前是否已经结束最上层的对象解析,即整个json字符串对象的解析。第三个字段parseState,一个用数组简单实现的栈类型数据结构,每进入到数组类型的解析或者进入到嵌套对象类型的解析时,都会往这个栈上压入一个int数据(这个int数据是个简单的标志位,会用到数组类型的解析和嵌套对象类型的解析中,在后面的源码解析中可以看到)。在完成数组类型或者嵌套对象类型后,会弹出这个int数据。
第四个字段err,用于记录在当前解析遇到的错误。第五个字段bytes,用于记录已经解析的字符串长度,这个字段状态机本身是不会更新这个字段的,只会由外部来更新(这里目前我也有点不太清楚为什么)