Lua 如何创建一个函数,返回传递给它的第一个非nil、非空字符串?

Lua 如何创建一个函数,返回传递给它的第一个非nil、非空字符串?,lua,lua-table,Lua,Lua Table,我试图实现一个函数,该函数从传递给它的变量返回第一个非空字符串。不幸的是,其中一些变量可能为零,因此这种天真的方法 function first_non_empty(...) for i, item in ipairs({...}) do if item ~= nil and item ~= '' then return item end end return '' end 不起作用:IPAIR遇到nil值时立即退

我试图实现一个函数,该函数从传递给它的变量返回第一个非空字符串。不幸的是,其中一些变量可能为零,因此这种天真的方法

function first_non_empty(...)
    for i, item in ipairs({...}) do
        if item ~= nil and item ~= '' then
            return item
        end
    end
    return ''
end
不起作用:IPAIR遇到nil值时立即退出。可以通过更改要求使变量不能为零,或通过将长度传递给函数使表长度不必依赖于
ipairs
,或通过将所有参数包装在函数中使它们都不显式为零来解决此问题

function first_non_empty_func(...)
    for i, func in ipairs({...}) do
        local item = func()
        if item ~= nil and item ~= '' then
            return item
        end
    end
    return ''
end

function fn(p)
    local f = function() return p end
    return f
end

-- change callers to first_non_empty_func(fn(a), fn(b), fn(c))

然而,这两种解决方案都使功能原型复杂化。是否存在一个函数,该函数采用有序的参数列表,其中一些参数可能为nil,它返回这些参数中的第一个参数,这些参数既不是nil,也不是空字符串?

使用
table.pack
,它保留所有nil条目,并返回
n
字段中的条目数:

function first_non_empty_pack(...)
    local t = table.pack(...)
    for i = 1, t.n do
        local item = t[i]
        if item ~= nil and item ~= '' then
            return item
        end
    end
    return ''
end

更简单的方法是使用递归。没有创建额外的表,等等:

function first_non_empty(item, ...)
    if item ~= nil and item ~= '' then return item end
    return first_non_empty(...)
end
但是列表必须以一些结束标记结束。例如,布尔值'false',表示不存在非零、非空字符串。

select('#',…)
可用于获取所提供参数的数量,因此这里有一个不使用
table.pack
:

function first_non_empty_pack(...)
    for i = 1, select('#', ...) do
        local item = select(i, ...)
        if item ~= nil and item ~= '' then
            return item
        end
    end
    return ''
end

美好的另外,由于5.1中出现了
select
,而
table.pack
没有,我可以将它与Scribunto一起使用。@chrismidgeley
function table.pack(…)返回{n=select('#',…),…}end
就是全部。对于长的vararg列表,重复复制
select
调用的列表可能比创建一次表并在其上迭代要慢。在另一个方向上,创建需要稍后进行垃圾收集的表可能会更慢。因此,基准测试以查看您的情况下哪一个更快(或者只选择您认为更干净的一个,直到您看到速度实际上是一个问题)。不需要结束标记,
select('#',…)==0
可以用作停止条件。避免重复调用
select
的另一种方法是先确定计数,然后倒计时,如
do local function rec(n,item,…)中所述,如果item~=nil和item~='',则返回item elseif n>0,然后返回rec(n-1,…)end function first_non_empty(…)return rec(select(“#,…),…),…)end end
。具有结束标记使此函数更快、更简单。此外,结束标记可以不是布尔值,而是一些回退字符串值,当找不到其他字符串时应返回该值。这将在该函数之外保存一些检查。这完全取决于实际需要,而此函数只是选项之一:)