Redis Lua 脚本未按预期工作

Redis Lua script not working as expected

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

引用自 MDN,

The copyWithin() method copies the sequence of array elements within the array to the position starting at target. The copy is taken from the index positions of the second and third arguments start and 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

测试过程中,成功清除第一个测试用例:

测试用例:使用 copyWithin(0, 3)

convert [1, 2, 3, 4, 5][4, 5, 3, 4, 5]
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]

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

测试用例:使用 copyWithin(0, 3, 4)

convert [1, 2, 3, 4, 5][4, 2, 3, 4, 5]
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}

循环中有什么可疑的地方吗?任何帮助都会很棒。

我通过修改脚本的以下部分解决了这个问题:

--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