首页 文章

Redis Lua脚本无法按预期工作

提问于
浏览
2

作为练习练习,我正在为Redis编写一个lua脚本,它基本上执行JavaScript方法Array#copyWithin() .

引用MDN,

copyWithin()方法将数组中的数组元素序列复制到从target开始的位置 . 副本取自第二个和第三个参数start和end的索引位置 .

这是我到目前为止写的脚本:

local list = redis.call('lrange', KEYS[1], 0, -1)
local target = tonumber(ARGV[1])
local startIndex = tonumber(ARGV[2])
local len = #list
local endIndex = len

--Handle negative startIndex
if startIndex < 0 then
    startIndex = len+startIndex
end

--If the third argument is provided, get the endIndex from it
if #ARGV > 2 then
    local arg = tonumber(ARGV[3])
    if arg >= 0 then
        if arg < endIndex then
            endIndex = arg
        end
    else
        if len+arg >= 0 then
            endIndex = len+arg
        else
            endIndex = 0
        end
    end
end

--An array containing the elements which will be copied
local targeted_elements = {}

--Fill elements from the list
for i=1, (endIndex-startIndex+1) do
    targeted_elements[i] = list[startIndex+i]
end

--Make sure no additional elements are pushed to the end of array in case of range overflow
local target_end = #targeted_elements

if target + target_end > len then
    target_end = len-target
end

--replace all the changed elements of the list in redis
for i=1, target_end do
    redis.call('lset', KEYS[1], target+(i-1), targeted_elements[i])
end

在测试期间,第一个测试用例被成功清除:

测试用例: convert [1, 2, 3, 4, 5] 进入 [4, 5, 3, 4, 5] 使用 copyWithin(0, 3)

LRANGE MyList 0 -1
> [1, 2, 3, 4, 5]

EVALSHA "sha1 of script" 1 MyList 0 3
(basically the same as `[1, 2, 3, 4, 5].copyWithin(0, 3)`)
> nil

LRANGE MyList 0 -1
> [4, 5, 3, 4, 5]

然而,第二个测试案例并没有那么顺利 .

测试用例: convert [1, 2, 3, 4, 5] 进入 [4, 2, 3, 4, 5] 使用 copyWithin(0, 3, 4)

LRANGE MyList 0 -1
> [1, 2, 3, 4, 5]

EVALSHA "sha1 of script" 1 MyList 0 3 4
(basically the same as `[1, 2, 3, 4, 5].copyWithin(0, 3, 4)`)
> nil

LRANGE MyList 0 -1
> [4, 5, 3, 4, 5]

经过一些调试后,我发现在两种情况下 targeted_elements 的值都是 {4, 5} ,而在情况2中它应该是 {4} .

循环中有什么可疑之处吗?任何帮助都会很棒 .

1 回答

  • 2

    我通过修改脚本的以下部分来修复此问题:

    --Fill elements from the list
    for i=1, (endIndex-startIndex+1) do
        targeted_elements[i] = list[startIndex+i]
    end
    

    将其改为:

    --Fill elements from the list
        for i=1, (endIndex-startIndex) do
            targeted_elements[i] = list[startIndex+i]
        end
    

    for 表达式中的 +1 向数组添加了一个额外的元素 . 它在第一种情况下起作用,因为所选部分来自 3, 5 ,所以 5-3+1 = 3 表示应该选择 3 元素 . 但由于只剩下 2 元素,案例仍然有效 .

    而对于第二种情况, 4-3+1 = 2 ,这意味着正在选择 2 元素,而不是 1 .

相关问题