Хе-хе, вот поэтому без внятного ТЗ результат ХЗ: не было ж ни слова про nil'овые дефолты. Вообще вариант у нас лишь один - всегда указывать размер таблицы defaults вручную, если в ней присутствует nil в конце, т.к. lua попросту не воспринимает его ни в случае вараргов, ни при инициализации таблицы напрямую:
print(#{nil, "b", "c"}) -- 3
print(#{"a", nil, "c"}) -- 3
print(#{"a", "b", nil}) -- 2
print(#{[1] = "a", [2] = "b", [3] = nil}) -- 2
Поэтому только ручками, видимо:
local function L(f, fArgsCount, defaults)
fArgsCount = fArgsCount or 1
if fArgsCount <= 1 then
return f
end
local fArgIndex = 1
local fArgs = {}
local function appendNextArg()
if fArgIndex > fArgsCount then
return f(table.unpack(fArgs, 1, fArgsCount))
end
return function(...)
local fArgsParts = {...}
if #fArgsParts == 0 then
fArgs[fArgIndex] = defaults and defaults[fArgIndex] or nil
fArgIndex = fArgIndex + 1
else
for i = 1, #fArgsParts do
fArgs[fArgIndex] = fArgsParts[i] or (defaults and defaults[fArgIndex] or nil)
fArgIndex = fArgIndex + 1
end
end
return appendNextArg()
end
end
return appendNextArg()
end
local function test(name, expectedResult, f)
local result = f()
print("[" .. (result == expectedResult and "Passed" or "Failed") .. "] " .. name .. ":")
print("Expected: " .. tostring(expectedResult))
print("Got: " .. tostring(result))
print()
end
test(
"test 1: no defaults, no result",
nil,
function()
f = L(function() print('succes!') end)
f()
end
)
test(
"test 2: no defaults, every argument is passed directly",
"a:1 b:2 c:3",
function()
f = L(
function(a, b, c) return 'a:' .. tostring(a) .. ' b:' .. tostring(b) .. ' c:' .. tostring(c) end,
3
)
return f(1)(2)(3)
end
)
test(
"test 3: no nils in defaults",
"a:a b:e c:c",
function()
f = L(
function(a, b, c) return 'a:' .. tostring(a) .. ' b:' .. tostring(b) .. ' c:' .. tostring(c) end,
3,
{'a', 'b', 'c'}
)
return f()('e')()
end
)
test(
"test 4: nil at defaults middle",
"a:a b:nil c:c",
function()
f = L(
function(a, b, c)
return 'a:' .. tostring(a) .. ' b:' .. tostring(b) .. ' c:' .. tostring(c)
end,
3,
{'a', nil, 'c'}
)
return f()()()
end
)
test(
"test 5: nil at defaults end",
"a:1 b:b c:3",
function()
f = L(
function(a, b, c)
return 'a:' .. tostring(a) .. ' b:' .. tostring(b) .. ' c:' .. tostring(c)
end,
3,
{'a', 'b', nil}
)
return f(1)()(3)
end
)
test(
"test 6: multiple returns, nil at defaults end",
"a:a b:2 c:nil",
function()
f = L(
function(a, b, c)
return 'a:' .. tostring(a) .. ' b:' .. tostring(b) .. ' c:' .. tostring(c)
end,
3,
{'a', 'b', nil}
)
return f(nil, 2)()
end
)
Фичу мульти-ретурна я сделал, фигня вопрос, однако если какая-то функция из цепочки вернет результат с nil в конце - система сдохнет. Тут уж либо опять вручную указывать кол-во аргументов, либо забить болт:
test(
"test 7: multiple returns with nil at end",
"a:a b:2 c:nil",
function()
f = L(
function(a, b, c)
return 'a:' .. tostring(a) .. ' b:' .. tostring(b) .. ' c:' .. tostring(c)
end,
3,
{'a', 'b', 'c'}
)
return f(2, nil)()
end
)