函数
Lua为面向对象式的调用提供了一种特殊的语法 - 冒号操作符。
o.foo(0.x) -> o:foo(x)
冒号操作符使调用 o.foo 时将 o 隐含地作为函数的第一个参数
特别注意,如果函数调用不是一系列表达式的最后一个元素,则只产生一个值
function funcA()
return 5, 10
end
local x, y = funcA(), 20
print(x .. " " .. y) -- 5 20
虽然 funcA内部 返回了两个值,但是作为表达式时,只产生了一个值
local x, y, z = funcA(), 20
-- z = nil
table 构造式可以接受一个函数的所有返回值,条件是只有当这个函数作为最后一个元素时才可以,在其它位置的话 只产生一个结果值
table = {funcA()} -- table = {5,10}
table = {funcA(),3} -- table = {5,3}
return 语句可以返回 funcA 的所有返回值
也可以将函数放入一对圆括号中,从而迫使它只返回一个结果
print((funcA())) -- 5
unpack 从下标1开始,返回数组的所有元素,以下是 lua 实现
function unpack(t,i)
i = i or 1
if t[i] then
return t[i] ,unpack(t,i+1)
end
end
print(unpack({10,20,30}))
变长参数
"…" 3个点表示可接受不同数量的实参,它的行为类似于一个具有多重返回值的函数,返回的是当前函数的所有变长参数。
具名实参
当实参只有一个 table 构造式时,函数调用中的圆括号是可有可无的
深入函数
Lua中,函数是一种”第一类值“,具有特定的词法域。
-
第一类值
表示函数与其它传统类型的值(数字,字符串)具有相同的权力,可以存储到变量或者table中,可作为实参传递给其它函数,可作为返回值 -
词法域
指一个函数可以嵌套在另一个函数中,内部函数可以访问外部函数的变量。
function funcA()
local a = 30
local function funcB()
print(a)
end
funcB()
end
Lua可以重新定义某些函数,甚至是重新定义那些预定义的函数。
举例,限制一个程序访问文件,利用 closure 来重定义函数 io.open
do
local oldOpen = io.open
local access_ok = function(fileName, mode)
-- <检查访问权限>
end
io.open = function(fileName, mode)
if access_ok(fileName, mode) then
return oldOpen(fileName, mode)
else
return nil, "access denied"
end
end
end
尾调用
判断标准:一个函数在调用完另一个函数后,是否就无其它事情需要做了。
下面这些都不是
return g(x) + 1 -- 需要做一次加法
return x or g(x) -- 必须调整为一个返回值
return (g(x)) -- 必须调整为一个返回值
-- 只有下面这种才是尾调用
return g(x)
closure(闭合函数)
简单来讲,一个 closure 就是一个函数加上该函数所需访问的所有“非局部的变量”
如果再次调用 values ,那么会创建一个新的局部变量 i ,得到一个新的 closure
- 非局部的变量
一个函数内部的函数可以访问到的变量就是 非局部的变量
非局部的变量会常驻在内存中,造成内存泄漏(有一块内存空间被长期占用,而不被释放)
function values(t)
local i = 0
return function ()
i = i + 1
return t[i]
end
end
local temp = {6,2,3,4,6}
local a = values(temp)
local b = values(temp)
print(a()) -- 6
print(a()) -- 2
此时 i 为非局部的变量,可以理解为全局变量,但是这个全局变量的作用域为一个闭合函数内。
一个持有外部环境变量的函数就是闭包。
local a = 10
function funA()
return a + 10
end
funA持有了外部变量 a ,所以funA是一个闭包函数