Подтвердить что ты не робот

В Lua, каков правильный способ обработки varargs, который содержит nil?

Я пытаюсь создать функцию отладки печати, которая принимает дескриптор файла в качестве первого аргумента. Во-первых, я пишу такую ​​функцию:

function fprint (f, ...)
   for i, v in ipairs{...} do
      f:write(tostring(v))
      f:write("\t")
   end
   f:write("\n")
end

Эта функция работает, пока я не передаю значение nil в аргументах. Но если я назову это с помощью nil, он не напечатает значение nil и остальные аргументы.

fprint(io.stderr, 1, 2, nil, 3)
=> prints only 1 and 2

Итак, как правильно решить эту проблему?

4b9b3361

Ответ 1

На самом деле, легко обрабатывать значения nil в varargs, все, что вам нужно, это использовать функцию select, которая работает даже с nil (он подсчитывает фактическое количество параметров). Следующая идиома настолько полезна, что она является основной библиотечной функцией table.pack в Lua 5.2:

function table.pack(...)
  return { n = select("#", ...), ... }
end

Количество аргументов сохраняется в поле n, поэтому для их повторения используйте это:

function vararg(...)
    local args = table.pack(...)
    for i=1,args.n do
        -- do something with args[i], careful, it might be nil!
    end
end

Ответ 2

Насколько я знаю, нет простого независимого способа реализации длины массива, содержащего записи nil, поскольку операция # может указывать на любую позицию, за которой следует nil, но это решение, зависящее от быстрой реализации, которое напечатает nil.

function fprint (f, ...)
   local parm={...}
   for i=1,#parm do
      f:write(tostring(parm[i]))
      f:write("\t")
   end
   f:write("\n")
end

Вместо ретрансляции на # вы можете получить сложный (и, следовательно, независимый от реализации), поскольку вы знаете, что таблица parm представляет собой массив и использует что-то вроде этого:

function last_index(array)
  local max = 0
  for k, _ in pairs(array) do
    max = math.max(max, k)
  end
  return max
end

function fprint (f, ...)
   local parm={...}
   for i=1,last_index(parm) do
      f:write(tostring(parm[i]))
      f:write("\t")
   end
   f:write("\n")
end

Если вы можете пропустить значения nil, и порядок не важен, то переход на pairs будет намного проще.