Lua中的布尔值在redis中没有预期的行为。

我有一个脚本

local fields = redis.call('hkeys', 'a:hash:full:of:stuff');
local retval = {};
for i, field in pairs(fields) do
    if((string.match(tostring(field),'ev')) ~= nil) then
        retval[i] = {field, (string.match(tostring(field),'ev') ~= nil) }
    end
end
return retval

这个脚本返回一个空列表

当我将if语句更改为以下形式时

if((string.match(tostring(field),'.')) ~= nil) then
    ...

我得到了一个包含以下内容的长列表

...
...
60) 1) "applet:1:metric:viewelement:20130607"
    2) (nil)
61) 1) "applet:1:total_events:20130529"
    2) (integer) 1
...
...

如果我用以下语句替换 if 语句

if(1)

我得到相同的长键列表

我也尝试过使用string.find,它的行为类似。

唯一看起来像模式的是,if语句将通过如果匹配的字符串在字符串中出现多次,或者出现在开头。我不能确定,但这可能有所帮助。

我使用以下命令运行此脚本

$ redis-cli eval "$(cat get_keys.lua)" 0
点赞
用户392975
用户392975
  1. 你不需要写 if((string.match(tostring(field),'ev')) ~= nil)。直接写成 if(string.match(tostring(field),'ev')) 即可。
  2. 你的脚本失败的原因是,Lua 不支持在表中使用空键。如果你设置 some_table[1]some_table[2]some_table[5],然后返回该数组,它看起来像是以 some_table[2] 结束。由于只有当 if 语句通过时才设置数组,如果在 retval[1] 失败,则不会返回其余的数组。

简单解决方法是:

local fields = redis.call('hkeys', 'a:hash:full:of:stuff');
local retval = {};
for i, field in pairs(fields) do
    if(string.match(tostring(field),'ev')) then
        retval[i] = {field, (string.match(tostring(field),'ev') ~= nil) }
    else retval[i] = 'some_nil_value'
    end
end
return retval

我认为你也可以使用[表的默认值](http://www.lua.org/pil/13.4.3.html),但我还没有尝试过,所以在这里不能给出太多信息。

**[编辑]**原帖写道他不想要 nil 的占位符。在这种情况下,可以使用以下代码:

local fields = redis.call('hkeys', 'a:hash:full:of:stuff');
local retval = {};
for i, field in pairs(fields) do
    if(string.match(tostring(field),'ev')) then
        retval[#retval+1] = {field, (string.match(tostring(field),'ev') ~= nil) }
    end
end
return retval
2013-06-10 19:58:41
用户1020076
用户1020076

Eli 的答案是有效的,但我认为问题的原因在于 Lua 处理列表的方式中存在微妙的陷阱。我想解释一下我认为正在发生的事情。

因此,作为测试,我在 retval 中插入了一个额外的字段,有时它为空。我注意到,在这些调用中,列表的其余部分没有被返回。

我认为在底层发生的事情是 Redis 会遍历整个列表,但当它被返回时,它会在第一个 nil 处被截断。因此,有时会有列表,有时则没有。为了破解这个问题,我将脚本重写为

local fields = redis.call('hkeys', 'a:hash:full:of:stuff');
local retval = {};
local i = 0
for j, field in pairs(fields) do
    if string.find(field,"ev") then
        retval[i] = {field, string.match(field,'ev') }
        i = i+1;
    end
end
return retval

这也工作了!

因此 Eli 的答案有效,因为 retval 没有被截断。但是,当需要遍历返回的列表时,它将占用更多的带宽和 CPU 时间。

2013-06-10 20:17:27