如何创建一个函数,返回第一个非 nil 和非空字符串?

我正在尝试实现一个函数,它可以从传递给它的变量中返回第一个非空字符串。不幸的是,其中一些变量可能为 nil,所以简单的方法

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

是行不通的:ipairs 会在遇到 nil 值时终止。这可以通过改变要求,使变量不能为 nil,或者通过将参数的长度传递给函数,以便表长度不必依赖 ipairs,或者通过将所有参数包装在一个函数中,使它们均不显式为 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

-- 调用者改为 first_non_empty_func(fn(a), fn(b), fn(c))

但这两个解决方案都使函数原型复杂化了。是否存在一个函数,它接受一个有序列表的参数,其中一些可能为 nil,并返回其中第一个既非 nil 也不是空字符串的参数呢?

点赞
用户107090
用户107090

使用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
2017-04-14 11:38:55
用户5675002
用户5675002

更简单的方法是使用递归。不需要创建额外的表等:

function first_non_empty(item, ...)
    if item ~= nil and item ~= '' then return item end
    return first_non_empty(...)
end

但是列表必须以某个结束标记结束。例如,布尔值 'false' 表示没有非空的字符串。

2017-04-14 15:44:57
用户1442917
用户1442917

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
2017-04-14 17:01:29