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
。
作为练习,我正在为 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
。