Corona SDK json库异常

大家好 对于任何人来说,在Corona SDK的项目中使用json都可以使某些事情变得很方便并不是什么秘密。 我发现使用该库时有一个有趣的异常现象,正如实践所示,这完全不是错误,而是您应该了解和准备的功能。 让我们详细考虑所有内容。

1.问题描述


假设我们有一个如下的Lua数组:

ar = {23,45,56,'weer'} 

如果您对语言有理解的所有正常知识,则将向您显示此数组,如下所示,由于情况的原因,该数组只是低脂-所以:

 ar = {[1] = 23,[2] = 45,[3] = 56,[4] = 'weer'} 

如果您决定将此数组转换为json,则输出将为您提供以下内容(当然,我们不会忘记连接json库):

 ar = {[1] = 23,[2] = 45,[3] = 56,[4] = 'weer'} json = require "json" local str = json.encode(ar) print(str)--> [23,45,56,"weer"] 

如您所见,json还知道这种简化记录的存在,如果数组中的元素按顺序排列,它们将不会被显式编号,这很妙,因为我们经常在我们的项目中使用json来实现网络协议或保存到文件,而多余的大小完全不存在什么。

现在,让我们尝试将流失转换回Lua表并显示其内容,同时注意键的数据类型:

 local str = '[23,45,56,"weer"]' local ar2 = json.decode(str) for k,v in pairs(ar2)do print(k,type(k),v) end --[[ 1 number 23 2 number 45 3 number 56 4 number weer ]] 

如您所见,结果超出预期,输入端的表ar与输出端的表ar2完全对应。 现在,按照前面的2点,但同时会有一个数组,其中数组中有一个中断的序列,比方说我们将键6(绕过5)添加为值“ wtf”。 我们要打破了。

 json = require "json" ar = {23,45,56,'weer',[6] = 'wtf'} local str = json.encode(ar) print(str)-->[23,45,56,"weer",null,"wtf"] local t = json.decode(str) for k,v in pairs(t)do print(k,type(k),v) end --[[ 1 number 23 2 number 45 3 number 56 4 number weer 6 number wtf ]] 

如您所见,一切都变得很好,因为json.encode期望此捕获,而不是插入一个不存在的5键null并全部成功结束,所以我们不会就此止步,并将另一个值为1的键777添加到数组中,很可能是我们期望的该表将以相同的方式进行转换,并将包含770 null-这肯定不是最佳选择,因为它将占用更多空间,但是json中根本没有其他方法来创建此lua表的完整模拟,因为键不在json中可能很清楚 vlen作为一个数字。 我们看看发生了什么。

 json = require "json" ar = {23,45,56,'weer',[6] = 'wtf',[777] = 1} local str = json.encode(ar) print(str)-->{"1":23,"2":45,"3":56,"4":"weer","6":"wtf","777":1} local t = json.decode(str) for k,v in pairs(t)do print(k,type(k),v) end --[[ 1 string 23 777 string 1 3 string 56 2 string 45 4 string weer 6 string wtf ]] 

如您所见,编码器采用另一种方式,将所有具有值类型数字的键转换为字符串。 众所周知,这样的功能会并且会导致错误(如果您不知道的话),或者在使用此表时使用显式的tonumber / tostring转换拐杖,这在任何情况下都不会带来太多乐趣。 考虑如何处理。

2.解决问题


为了解决这个问题,您可以编写一个函数来初始化出现问题的所有数组,然后在代码中必须不断记住该问题并将其应用于所有地方,这是一种正常方法,但不是最佳方法,因此有计划B重新定义json.decode函数的实现,以便所有问题区域都将自动转换,并且该解决方案将在传递的数组中的第一个嵌套以及更深的附件上都起作用。 将json库连接到项目后,我们将立即重新定义函数值。 可以使用以下实现:

 json = require "json" local jd = json.decode--   local norm_ar json.decode = function(ar,not_convert)--  local res = jd(ar) --     --    norm_ar = function(root) local res = {} --  for k,v in pairs(root)do res[k] = v end --   for k,v in pairs(res) do if type(k) == 'string' and--  string.match(tostring(k),'%D') == nil then--    -- string -> number root[tonumber(k)] = root[k] root[k] = nil--   end --      if type(v) == 'table' then norm_ar(v) end end return root end --   not_convert    return not_convert and res or norm_ar(res) end 

现在尝试再次执行先前的操作:

 ar = {23,45,56,'weer',[6] = 'wtf',[777] = 1} local str = json.encode(ar) print(str)-->{"1":23,"2":45,"3":56,"4":"weer","6":"wtf","777":1} local t = json.decode(str) for k,v in pairs(t)do print(k,type(k),v) end --[[ 1 number 23 2 number 45 3 number 56 4 number weer 6 number wtf 777 number 1 --]] 

如您所见,一切正常,数组保留了以前的结构。 最后,我想补充一点,如果由于某种原因需要避免这种转换,新的json.decode实现选项支持第二个可选参数,该参数将禁用转换。

再见!

Source: https://habr.com/ru/post/zh-CN422591/


All Articles