Lua 函数--函数

        在Lua中,函数是一种对语句和表达式进行抽象的主要机制。函数既可以完成某项特定的任务,也可以只做一些计算并返回结果。

        Lua具有一项非常于总不同的特征,允许函数返回多个结果:

s, e = string.find("Hello Lua users", "Lua")
print(s, e)            -->7    9

        以Lua编写的函数同样可以返回多个结果,只需在return关键字后列出所有返回值即可:

function maximum (a)
local mi = 1            --最大值的索引
local m = a[mi]         --最大值
    for i, val in ipairs(a) do
        if val > m then
            mi = i; m = val
        end
    end
return m, mi    
end

print(maximum({8, 10, 23, 12, 5})        -->23    3

        关于多重返回值还要介绍一个特殊函数--unpack。它接受一个数组作为参数,并从下标1开始返回该数组的所有元素:

print(unpack{1, 2, 3})        -->1    2    3
a, b = unpack{1, 2, 3}        -->a=1, b=2, 3被丢弃

        Lua中的函数还可以接受不同数量的实参:

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

print(add(3, 4, 10, 25, 12))            -->54

        参数表中的3个点(...)表示该函数可接受不同数量的实参。实际上,还可以通过变长参数来模拟Lua中普通的参数传递机制,例如:

function foo(a, b, c)
--可以转换为:
function foo(...)
local a, b, c = ...
end

        Lua提供了专门用于格式化文本(string.format)和输出文本(io.write)的函数。很自然地会想到将这两个函数合二为一:

function fwrite(fmt, ...)
return io.write(string.format(fmt, ...))
end

--调用                    参数
fwrite()                 fmt = nil,没有变长参数
fwrite("a")              fmt = "a",没有变长参数
fwrite("%d%d", 4, 5)     fmt = "%d%d",变长参数为4和5

        在Lua中,函数是一种“第一类值”,这表示在Lua中函数与其他传统类型的值具有相同的权利。函数可以存储到变量中或table中,可以作为实参传递给其他函数,还可以作为其他函数的返回值。

        在Lua中有一个容易混淆的概念是,函数与所有其他值一样都是匿名的,即它们都没有名称。当讨论一个函数名是(例如print),实际上是在讨论一个持有某函数的变量。

a = {p = print}
a.p("Hello World")        -->Hello World
print = math.sin          --'print'现在引用了正弦函数
a.p(print(1))             -->0.841470
sin = a.p                 --'sin'现在引用了print函数
sin(10, 20)               -->10    20

        “词法域”是指一个函数可以嵌套在另一个函数中,内部的函数可以访问外部函数中的变量。

function newCounter()
local i = 0
    return function()        --匿名函数
                i = i + 1
           return i
           end
end

c1 = newCounter()
print(c1())        -->1
print(c1())        -->2

        在这段代码中,匿名函数访问了一个“非局部的变量”i,调用i 时并没有超出作用范围。一个closure(闭合函数)就是一个函数加上该函数所需访问的所有“非局部的变量”。如果再次调用newCounter,那么它会创建一个新的局部变量i,从而也将得到一个新的closure:

c2 = newCounter()
print(c2())        -->1
print(c1())        -->3
print(c2())        -->2

        将函数储存在table中:

Lib = {
    foo = function(x, y) return x+y end,
    goo = function(x, y) return x-y end
}

Lib = {}
function Lib.foo(x, y) return x+y end
function Lib.goo(x, y) return x-y end

        将函数储存在局部变量中:

local fact
fact  = function(n)
if n == 0 then return 1
    else return n*fact(n-1)
end
end   

-- local fact = function(n) .......        --用这种方式定义递归是错误的,因为调用fact(n-1)时,局部的                                            --fact尚未定义完毕

        当一个函数调用时另一个函数的最后一个动作时,该调用称为“尾调用”,“尾调用”不会耗费栈空间(“尾调用消除”)。

function f(x)
    return g(x)
end

return x[i].foo(x[j]+a*b, i+j)

         以下调用都不符合尾调用准则(一个函数在调用完另一个函数之后,是否就无其他事情需要做了):

return g(x)+1        --必须做一次加法
return x or g(x)     --必须调整为一个返回值
return (g(x))        --必须调整为一个返回值

function func(...)
    local mytable = {...}
    for k, v in pairs(mytable) do
        print(k, v)
    end
end

func("123", 12, "ok")        -->1    123
                             -->2    12
                             -->3    ok

上一篇:【Python小试】使用列表解析式简化代码


下一篇:C# 匿名函数 详解