Lua: Language: Function

 9th November 2022 at 12:07pm

基础

Lua 的函数参数,只有位置参数(positional),没有命名参数。

函数调用的简化写法

当参数只有一个、且为 string literal 或 table constructor 时,调用一个函数时参数列表可以不用 () 包裹:

print "hello world"    -- 等同于 print("hello world") 
type{}                 -- 等同于 type({})

但我觉得这种节约没有意义。

参数匹配

调用函数时,Lua 不要求传参数量一致:

function f(a, b)
    print(a, b)
end

f()          --> nil    nil
f(3)         --> 3      nil
f(3, 4)      --> 3      4
f(3, 4, 5)   --> 3      4       (5 被丢弃)

参数默认值

function incCount(n)
    n = n or 1   -- 用这种写法实现参数默认值的能力
    globalCounter = globalCounter + n
end

函数多返回值

Lua 支持多返回值;支持在一个语句(statement)中实现多次赋值(multiple assignments)。但多返回值的机制有点 tricky:仅当多返回值的函数,作为多赋值语句中的唯一或最后一方时,它的多个值都会被返回;不然仅使用其第一个值。代码表示下:

function foo0 () end
function foo1 () return "a" end
function foo2 () return "a", "b" end

x, y = foo2()           --> x="a", y="b"
x = foo2()              --> x="a", "b" is discarded
x, y, z = 10, foo2()    --> x=10, y="a", z="b"

x, y = foo0()           --> x=nil, y=nil
x, y = foo1()           --> x="a", y=nil
x, y, z = foo2()        --> x="a", y="b", z=nil

-- 函数不在最后一位时,仅有第一个返回值起作用
x, y = foo2(), 20        --> x="a", y=20 ("b" is discarded)
x, y = foo0(), 20, 30    --> x=nil, y=20 (30 is discarded)

print(foo2())           --> a   b
print((foo2()))         --> a
print(foo2(), 1)        --> a   1
print(foo2() .. "x")    --> ax

t = {foo2()}                --> t = {"a", "b"}
t = {foo0(), foo2(), 4}     --> t[1] = nil, t[2] = "a", t[3] = 4

本质上是 Lua 的多返回值机制设计得不够严谨。如果像 Python 一样有 tuple 来承载多返回值,就不需要搞得这么复杂。

可变参数函数

就是把 ... 当成多个值:

function add (...)
    local s = 0 for _, v in ipairs{...} do
        s = s + v
    end 
    return s
end

print(add(3, 4, 10, 25, 12))    --> 54
function p(...)
    local a, b = ...
    print(a, b)
end

p(1)        --> 1   nil
p(3, 4)     --> 3   4
function p2(...)
    print(...)
    print(..., 10)
    print(20, ...)
end

-- 跟函数多返回值一样,不在最后面时就仅有第一个值起效
> p2(3, 4)
3   4
3   10
20  3   4

-- `unpack` 函数(Lua 5.1)及后面的 `table.unpack` 函数(Lua 5.2 起),
-- 可以把一个 table unpack 成多个参数
t = {"hello", "world"}
print(table.unpack(t))