lua程序设计(3) - 深入函数

1、closure闭包

lua也支持类似js的闭包,工作性质和工作流程也一样

1.1 可变长度参数:

printResult = “”
function print(…)
for i, v in ipairs(arg) do
printResult = printResult .. tostring(v) .. “\t”
end
printResult = printResult .. “\n”
end

数参数列表中的三点(…)表示该函数有可变数量的参数。当该函数被调用的时候,它所有的参数会被存入一个表变量,该变量是一个名为arg的隐藏变量,表中除了存储所有的参数之外,还附带一个额外的域n用来存储参数的个数。

function g(a, b, …)
end
CALL PARAMETERS
g(3) a = 3, b = nil, arg = {n = 0}
g(3, 4) a = 3, b = 4, arg = {n = 0}
g(3, 4, 5, 8) a = 3, b = 4, arg = {5, 8; n = 2}

2、用变量定义函数

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

3、尾调用

function f(x)
return g(x)
end

尾调用时不耗费任何栈空间,所以尾调用不会溢出
注意下面这段代码不是尾调用

function f(x)
g(x)
end

4、loadstring执行字符串代码,使用全局的作用域,这个函数
f = loadstring(“ i = i + 1”)

如果代码中有错误,loadstring会返回nil

5、if not n then error(“invalid input”) end 这段代码相当于
n = assert(io.read(“*number”), “invalid input”)

6、assert函数检查其第一个参数是否true,如果为true则返回该参数,否则引发一个错误,抛出第二个参数

7、pcall()用来做异常控制

pcall 会以一种保护模式来运行函数,如果没有发生错误,pcall第一个返回true,第二个及以后返回函数返回值,如果出现错误,第一个参数返回false,以后的参数返回错误信息

8、获得错误的堆栈信息xpcall,该函数可以打印堆栈信息

function f()
local x;
error(‘aaa’)
end

local s= xpcall(f,function ()
print(debug.traceback())
end
)
print(s)

输出:

stack traceback:
lua1.lua:7: in function lua1.lua:6
[C]: in function ‘error’
lua1.lua:3: in function lua1.lua:1
[C]: in function ‘xpcall’
lua1.lua:6: in main chunk
[C]: ?
false

9、协同程序

协同程序就相当于不能独立运行的线程,与其他协同程序共同享有全局变量,但是同一时刻只能有一个协同程序在工作

10、创建一个简单的协同程序

co = coroutine.create(function () print(“hi”) end)
print(co) – thread: 0081C330

11、查看一个协同程序的状态

print(coroutine.status(co)) –suspended

12、启动或再次启动一个协同程序

coroutine.resume(co)
print(coroutine.status(co)) –dead

13、协同程序可以让一个程序在运行中挂起,然后等待恢复继续执行,比如下面代码:

co = coroutine.create(function()
for i=0,10 do
print(“co”,i)
coroutine.yield()
end
end
)
coroutine.resume(co) –co –1
print(coroutine.status(co)) –suspended

coroutine.resume(co) –co – 2
coroutine.resume(co) –co – 3
coroutine.resume(co) –co –4
… …
coroutine.resume(co) –co –10
coroutine.resume(co) –co –什么都不打印
print(coroutine.resume(co)) –false cannot resume dead coroutine

14、当协同程序发生错误,lua不会显示错误消息,而是将执行权交给resume调用。

15、当一个协同程序A唤醒另外一个协同程序B,则A就处于一个特殊状态,正常normal

16、协同程序的返回值

例1:
co = coroutine.create(function(a,b)
coroutine.yield(a+b,a-b)
end
)
print(coroutine.resume(co,20,10)) – true 30 10

例2:

co = coroutine.create(function(a,b)
print(“co”, coroutine.yield())
end
)
print(coroutine.resume(co)) – true
print(coroutine.resume(co,20,10)) –true

返回

true
co 20 10
true

例3:

co = coroutine.create(function(a,b)
return 6, 7
end
)
print(coroutine.resume(co)) – true 6 7

17、协同程序的经典示例就是生产者-消费者,一个程序不停的生产值,另一个程序不停的消费这个值

18、协同程序的一个例子:http爬虫,可以并发的去爬内容