我一直在阅读关于cjson的文档,知道null值转换为 cjson.null 值(因为在 Lua 表中没有办法存储 nil。如果我使用cjson.decode和cjson.encode的话,效果很好。
然而,当我尝试用 cmsgpack,空值的键不存在。我使用类似这样的代码 一个.
你是如何解决这个问题的?你是用一个特殊的值来替换null值(在调用cmspack.pack之前,{isnull: true},然后再把{isnull: true}替换回null)还是用其他技术?
我做了一个快速的研究,没有找到任何 msgpack 库来处理 null
值的哈希表。不过我并不是说不存在这样的库。
我选择了另一种方法。由于 lua-cmsgpack
不做任何特殊处理 null
解码MessagePack二进制数据时的值和 nil
值只在表中有问题,我们可以为哈希→表解码器增加一些特殊情况的代码。
其实,这个补丁是很简单的。
--- a/lua_cmsgpack.c
+++ b/lua_cmsgpack.c
@@ -565,6 +565,10 @@ void mp_decode_to_lua_hash(lua_State *L, mp_cur *c, size_t len) {
mp_decode_to_lua_type(L,c); /* key */
if (c->err) return;
mp_decode_to_lua_type(L,c); /* value */
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 1);
+ lua_pushlightuserdata(L, NULL);
+ }
if (c->err) return;
lua_settable(L,-3);
}
这里的第二个调用 mp_decode_to_lua_type
转换一个哈希条目 价值 到一个对应的Lua类型值,当该值为 nil
(即: null
在MessagePack中),我们用一个轻量级的用户数据来代替它(NULL
指针)。) 同样的用户数据(NULL
指针)被用作 cjson.null
值。
我们不需要给编码器打补丁,因为它可以将任何不支持的值,包括任何用户数据编码为 null
,也就是说,你可以使用 cjson.null
用户数据来代表 null
值(cjson.decode就是这样做的)。当哈希值被解码后,你会得到相同的userdata。
同样的技巧也可以应用于类似数组的表,但如果你知道表的大小,就没有必要了--你可以从第一个索引到最后一个索引对表进行迭代。
local cjson = require('cjson')
local cmsgpack = require('cmsgpack')
local encoded_hash = cmsgpack.pack({k1 = nil, k2 = cjson.null, k3 = 'baz'})
local decoded_hash = cmsgpack.unpack(encoded_hash)
print('decoded_hash.k2 == cjson.null?', decoded_hash.k2 == cjson.null)
for k, v in pairs(decoded_hash) do
print(k, '->', v)
end
local encoded_array = cmsgpack.pack({'foo', nil, cjson.null, 'bar'})
local decoded_array = cmsgpack.unpack(encoded_array)
print('#decoded_array =', #decoded_array)
for i = 1, 4 do
print(i, '->', decoded_array[i])
end
输出。
decoded_hash.k2 == cjson.null? true
k3 -> baz
k2 -> userdata: (nil)
#decoded_array = 4
1 -> foo
2 -> nil
3 -> userdata: (nil)
4 -> bar
多亏了LuaRocks,我们甚至不需要支持库的fork就能完成这样一个琐碎的补丁。补丁可以直接包含在rockspec文件中。我用修改后的rockspec创建了一个gist。https:/gist.github.comun-defd6b97f5ef6b47edda7f65e0c6144663c
你可以用下面的命令安装一个打过补丁的库。
luarocks install https://gist.github.com/un-def/d6b97f5ef6b47edda7f65e0c6144663c/raw/8fe2f1ad70c75bfe2532a1f4cf9213f4e28423d3/lua-cmsgpack-0.4.0-0.rockspec