前言最近写的json解析库xjson,之前一直在持续优化,主要优化了两个方面。首先是支持将JSONObject对象输出为JSON字符串。在以前的版本中,它只是使用内置的Print函数来打印数据:funcTestJson4(t*testing.T){str:=`{"people":{"name":{"first":"bob"}}}`首先:=xjson.Get(str,"people.name.first")assert.Equal(t,first.String(),"bob")get:=xjson.Get(str,"people")fmt.Println(get.String())//assert.Equal(t,get.String(),`{"name":{"first":"bob"}}`)}Output:map[name:map[first:bob]]经过这次优化,可以直接输出JSON字符串:实现过程也很简单,只需要递归遍历对象中的数据,然后拼接字符串即可。核心代码如下:func(rResult)String()string{switchr.Token{caseString:returnfmt.Sprint(r.object)caseBool:returnfmt.Sprint(r.object)caseNumber:i,_:=strconv.Atoi(fmt.Sprint(r.object))返回fmt.Sprintf("%d",i)caseFloat:i,_:=strconv.ParseFloat(fmt.Sprint(r.object),64)returnfmt.Sprintf("%f",i)caseJSONObject:returnobject2JSONString(r.object)caseArrayObject:returnobject2JSONString(r.Array())default:return""}}带位操作的优化第二次优化主要是提升性能,查询一个复杂的JSON数据,性能提升约?16%。#优化前,BenchmarkDecode-129001366905ns/op42512B/op1446allocs/op#OptimizedBenchmarkDecode-1210474659766ns/op37749B/op1141allocs/op这里有一些关键的变化:JSON解析过程中会有一个有限状态机的状态转换,和多个状态可能会在迁移过程中出现。比如当前解析的token值是{,那么它的下一个token可能是ObjectKey:"name",也可能是BeginObject:{,当然也可能是EndObject:},所以在优化之前,我把所有的state都存起来了在一个集合中。如果解析时状态不符合预期的列表,则会抛出语法异常错误。所以在优化前先遍历集合进行判断。时间复杂度是O(N),但是当我们切换到位操作时,时间复杂度直接变成了O(1),同时节省了一个分片的存储空间。下面简单分析下为什么这个位操作可以达到判断一条数据是否在集合中的效果。首先以这两个状态为例:StatusObjectKeystatus=0x0002StatusColonstatus=0x0004它们对应的二进制数据是:StatusObjectKeystatus=0x0002//0010StatusColonstatus=0x0004//0100我们在计算|操作这两个数据的时候,我们得到的数据是0110:A:0010B:0100C:0110这时候如果我们用这两个原始数据和C:0110做&运算,就会还原成刚才的两个数据。//input:A:0010C:0110//output:A:0010------------//input:B:0100C:0110//output:B:0100但我们改变D和C来找到&When:D:1000//0x0008对应二进制1000C:0110D':0000,会得到0值。只要得到的数据大于0,我们就可以判断一个数据是否在给定的集合中。当然,这里有一个前提,就是我们输入的数据的高位永远为1,也就是2的幂。在解析查询语法的时候也使用了同样的优化:其他奇葩技巧当然还有一些其他的位运算的技巧,比如判断奇偶数://偶数a&1==0//奇数a&1==1乘除法,右移一位除以2,移位向左一位是乘以2.x:=2fmt.Println(x>>1)//1fmt.Println(x<<1)//4位运算总结在提高程序性能的同时,也降低了代码的可读性,所以我们要根据自己的需要来选择是否使用;对于极度追求性能,但又在业务代码中加入数据的场景,推荐一些底层库和框架代码。减法、乘法、除法都不需要使用位运算,只会让后续的维护者一头雾水。相关代码:https://github.com/crossoverJie/xjson
