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

2013-03-09 18:04

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

by snoopyxdy

at 2013-03-09 10:04:41

original http://snoopyxdy.blog.163.com/blog/static/60117440201312564742232

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爬虫,可以并发的去爬内容
page 82