如何创建一个 returns 传递给它的第一个非零、非空字符串的函数?

How do I create a function that returns the first non-nil, non-empty string passed to it?

我正在尝试实现一个函数,该函数 returns 传递给它的变量中的第一个非空字符串。不幸的是,其中一些变量可能为零,所以天真的方法

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

不起作用:ipairs 在遇到 nil 值时立即退出。这可以通过更改要求使变量不能为零来解决,或者通过将长度传递给函数以便 table 长度不必依赖于 ipairs,或者通过包装所有函数中的参数,以便其中 none 明确为 nil

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,returns 第一个既非 nil 又非空字符串的参数?

使用 table.pack,它保留所有 nil 条目和 returns 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

但是列表必须以一些结束标记结束。例如,boolean '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