Lua:lua-cjson:Cannot serialise table: excessively sparse array
Code:
local cjson = require "cjson"
local cjson2 = cjson.new()
local array = {}
array[19] = 19
cjson2.encode(array)
执行时异常:
Cannot serialise table: excessively sparse array
查阅 cjson.encode API 手册:
在编码 Json 数组时,lua-cjson 按照缺失的数值数目将 Lua table 分为三类:
1)标准型(Normal)
例如:
local array = {}
array[1] = 1
array[2] = 2
array[3] = 3
数组大小是3,数组第1、2、3个元素都存在。
2)稀疏型(Sparse)
例如:
local array = {}
array[1] = 1
array[2] = 2
array[9] = 9
数组长度是9,但除了第1、2、9个元素存在外,其余的元素都不存在(缺失6个元素),都为 null 值。
只要有一个元素缺失,就是稀疏型。(At least 1 value is missing.)
3)过度稀疏型(Excessively sparse)
例如:
local array = {}
array[19] = 19
数组长度是19,但是只有1个元素存在,缺失18个元素。
如何判断稀疏型和过度稀疏型界限呢?
An array is excessively sparse when all the following conditions are met:
ratio > 0
maximum_index > safe
maximum_index > item_count * ratio
先暂时不管 “ratio” 是啥,先看一个 API:
convert, ratio, safe = cjson.encode_sparse_array([convert[, ratio[, safe]]])
-- "convert" must be a boolean. Default: false.
-- "ratio" must be a positive integer. Default: 2.
-- "safe" must be a positive integer. Default: 10.
默认情况下,ratio 值为2,并且 convert 是 false。
查看源码:
Step 1:
执行 cjson.new 创建 cjson 实例对象时,会创建一个独立的默认参数配置信息到 cjson 实例对象中。
Step 2:
json_create_config 中创建了一个完全用户数据(内存)对象(默认参数配置表),并初始化其默认配置。
Step 3:
可以看到,默认配置:convert=false(0);ratio=2;safe=10。
回到原点,看看我们的 lua 脚本在编码时为何报错?
Lua table (array) 大小是 19,但是其中只有一个元素,缺失 18 个元素。
默认情况,ratio 是 2,maximum_index 是 19,item_count 是 1。
已经满足一下条件:
ratio(2) > 0
maximum_index(19) > safe(10)
maximum_index(19) > item_count(1) * ratio(2)
此 Lua table 属于过度稀疏型数组。
对于过度稀疏型数组在编码 Json 时将出异常报错。
By default, attempting to encode an excessively sparse array will generate an error.
于是执行 cjson.encode 时报错。
我们可以尝试从 lua-cjson 源码中查找报错字符串来定位错误位置:
查阅 lua_cjson.c 源码:
此处代码逻辑已经很清晰啦,就是我们上面 API 中描述的异常时的条件。
我们可以通过调用 encode_sparse_array 此 API 来设置一个 cjson 实例对象的参数配置,改变 ratio、convert、safe 的值。
由于我们仅仅是希望将 Lua table = {[19]=19} 可以正常地转换为 Json 字符串,所以仅需改变 convert 配置值即可。
If convert is set to true, excessively sparse arrays will be converted to a JSON object.
示例:
Code:
local cjson = require "cjson"
local cjson2 = cjson.new()
cjson2.encode_sparse_array(true)
local array1 = {}
array1[6] = 6
print(cjson2.encode(array1))
local array2 = {}
array2[19] = 19
print(cjson2.encode(array2))
执行结果:
最后,lua-cjson 的 encode 将过度稀疏型数组转换成了一个 Json 对象,而非是 Json 数组。
思考:
如果将 Lua table = {[19]=19} 转换为 Json 数组应该怎么做?
Lua 脚本:
local cjson = require "cjson"
local cjson2 = cjson.new()
cjson2.encode_sparse_array(false, 100)
local array2 = {}
array2[19] = 19
print(cjson2.encode(array2))
执行结果:
^_^
参考文档:
1.https://www.kyne.com.au/~mark/software/lua-cjson-manual.html#encode_sparse_array