预处理 ... 输入 - 错误参数 #2 到 'format'(无值)

Pre-process ... input - bad argument #2 to 'format' (no value)

我有一个场景,我想将输入输入到 printf 实现并预处理参数。我的目标是获取输入,在必要时处理变量参数 (...),然后将其输入 string.format。我遇到的问题是数据在传递时会“丢失”。我发现 ... 中的 nil 值没有传入。例如,如果正常 运行 通过 nil, false, false,则调用路径中的后续下线函数只会看到 false, false。当转换为内部 table ({...}) 进行处理时,我在这里缺少什么来保留数据?

编辑:我的初步评估不正确。 nil 永远不会被保留(即使在 printf 中)。如果打印 ...,则 table 可以为空(对于所有 nil)或仅在包含“真实”数据的位置具有索引值(例如 TablePrint 给出 { [2] = false, [3 ] = 假})

运行 在游戏中,但我可以在不使用任何游戏数据的情况下复制行为。

local function TablePrint (data, indent)
    if not indent then indent = 0 end

    local output = string.rep(" ", indent) .. "{\r\n"
    indent = indent + 2
    
    for k, v in pairs(data) do
        output = output .. string.rep(" ", indent)
        
        if (type(k) == "number") then
            output = output .. "[" .. k .. "] = "
        elseif (type(k) == "string") then
            output = output  .. k ..  "= "   
        end
        
        if (v == nil) then
            output = output .. 'nil' .. ",\r\n"
        elseif (v == NULL) then
            output = output .. 'NULL' .. ",\r\n"
        elseif (type(v) == "number") then
            output = output .. v .. ",\r\n"
        elseif (type(v) == "string") then
            output = output .. "\"" .. v .. "\",\r\n"
        elseif (type(v) == "table") then
            output = output .. TablePrint(v, indent + 2) .. ",\r\n"
        else
            output = output .. "\"" .. tostring(v) .. "\",\r\n"
        end
    end
    
    output = output .. string.rep(" ", indent-2) .. "}"
    
    return output
end

local function NormalizeValue(v)
    local output

    if (v == nil) then
        output = 'nil'
    elseif (v == NULL) then
        output = 'NULL'
    elseif (type(v) == "number" or type(v) == "string") then
        output = v
    elseif (type(v) == "table") then
        output = TablePrint(v)
    else
        output = tostring(v)
    end

    return output
end

local function NormalizeArgs(...)
    local args = {...}
    --print(TablePrint(args))
    local normalizedArgs = {}

    for _,v in ipairs(args) do
        table.insert(normalizedArgs, NormalizeValue(v))
    end

    return unpack(normalizedArgs)
end

local function printf(message, ...)
    --print(TablePrint({...}))
    local output

    if (type(message) == "number") then
        output = message
    elseif (type(message) == "string") then
        output = string.format(message, NormalizeArgs(...))
        --this call to string.format succeeds if used
        --output = string.format(message, ...)
    elseif (type(message) == "table") then
        output = TablePrint(message)
    else
        output = tostring(message)
    end

    print(output)
end

--this line fails since nil isn't preserved across call boundaries
--printf('initial conditions, cursor: %s, confirm window: %s, isfinished: %s', nil, nil, nil)
--this line fails since nil isn't preserved across call boundaries
printf('initial conditions, cursor: %s, confirm window: %s, isfinished: %s', nil, false, false)
--this will succeed
printf('initial conditions, cursor: %s, confirm window: %s, isfinished: %s', false, false, false)
--in the normal impl the final parameter is supplied by a call to a local function
printf('initial conditions, cursor: %s, confirm window: %s, isfinished: %s', gamelib.Cursor.ID(), gamelib.Window('Confirm').Open(), nil)

您可以使用select来全面检查...。递归地 return 多个值可能比创建 table 只是为了解压它更容易:

local function NormalizeArgs(...)
    if select('#', ...) > 0 then
        return NormalizeValue(select(1, ...)), NormalizeArgs(select(2, ...))
    end
end