Есть ли способ определить сигнатуру функции Lua?
Недавно Lee Baldwin показал, как написать универсальную функцию записи переменных в переменные. Я думал, что было бы лучше вернуть более простую функцию, где требуется только один параметр. Вот моя полная фиктивная попытка:
local function memoize(f)
local cache = {}
if select('#', ...) == 1 then
return function (x)
if cache[x] then
return cache[x]
else
local y = f(x)
cache[x] = y
return y
end
end
else
return function (...)
local al = varg_tostring(...)
if cache[al] then
return cache[al]
else
local y = f(...)
cache[al] = y
return y
end
end
end
end
Очевидно, чтоselect('#', ...)
терпит неудачу в этом контексте и не будет действительно делать то, что я хочу в любом случае. Есть ли какой-нибудь способ сказать внутри, запомни, сколько аргументов ожидает?
"Нет" - хороший ответ, если вы точно знаете. Нет ничего страшного в использовании двух отдельных функций памятки.
3 ответа
Я полагаю, вы могли бы перейти к отладочной информации и определить это по исходному коду, но в основном это "нет", извините.
Да, для функций Lua, но не для функций C. Это немного мучительно и немного схематично.
debug.getlocal
работает с вызываемыми функциями, поэтому вы должны вызвать соответствующую функцию. Это не показывает ни намека на ...
если вызов не передает достаточно параметров. Код ниже пытается 20 параметров.
debug.sethook
событие "call" дает возможность перехватить функцию, прежде чем она запустит какой-либо код.
Этот алгоритм работает с Lua 5.2. Старые версии будут похожи, но не одинаковы:
assert(_VERSION=="Lua 5.2", "Must be compatible with Lua 5.2")
Небольшой вспомогательный итератор (может быть встроен для эффективности):
local function getlocals(l)
local i = 0
local direction = 1
return function ()
i = i + direction
local k,v = debug.getlocal(l,i)
if (direction == 1 and (k == nil or k.sub(k,1,1) == '(')) then
i = -1
direction = -1
k,v = debug.getlocal(l,i)
end
return k,v
end
end
Возвращает подпись (но может возвратить счетчик параметров и использует вместо этого Varargs):
local function dumpsig(f)
assert(type(f) == 'function',
"bad argument #1 to 'dumpsig' (function expected)")
local p = {}
pcall (function()
local oldhook
local hook = function(event, line)
for k,v in getlocals(3) do
if k == "(*vararg)" then
table.insert(p,"...")
break
end
table.insert(p,k) end
debug.sethook(oldhook)
error('aborting the call')
end
oldhook = debug.sethook(hook, "c")
-- To test for vararg must pass a least one vararg parameter
f(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
end)
return "function("..table.concat(p,",")..")"
end