第七章 迭代器与泛型for
7.1 迭代器与closure
一个简单的迭代器示例:
function values(t)
local i=0
return function() i=i+1 ;return t[i] end
end
--在这里,values就是一个工厂,每次调用就产生一个新的closure(迭代器本身)
------------------------
--使用while循环中使用这个迭代器
t={10,20,30}
iter=values(t) --创建迭代器
while true do
local element=iter()
if element==nil then break end
print(element)
end
---------------
--使用for
t={10,20,30}
for element in values(t) do
print(element)
end
7.2 泛型for的语义
泛型for语法
for<var-list> in <exp-list> do
<body>
end
7.3无状态的迭代器
7.4具有复杂状态的迭代器
7.5真正的迭代器
第八章 编译,执行与错误
尽管lua是一种解释型语言,但是lua确实允许在运行前预编译为一种中间形式。
8.1编译
Lua有一种内置函数 dofile函数。
还有一种函数叫做loadfile函数,这个函数会从一个文件加载lua代码块,但是不执行,只是编译代码,将来代码作为一个函数返回。未完待续。
8.2 C代码
local path=”/user/local/lib/lua/5.1/sockec.so”
local f=package.loadlib(path,”luaopen_socket”)
loadlib函数加载指定的库,并将其链接入lua,不过他没有调用里面的任何函数,他只是将一个c函数作为lua函数返回。如果在加载库或者查找初始化函数时发生任何错误,loadlib返回nil及一条错误信息。loadlib函数必须提供完整的路径和正确的函数名称才行。
8.3错误
lua提供了assert对错误进行预测,比如
n=io.read()
assert(tonumber(n),"invalid input:"..n.."is not a number")
未完。
8.4错误处理与异常
在lua中处理错误可以使用pcall函数,假设在执行一段lua代码时,捕获所有的执行中引发的错误,那么第一步就是将这段代码封装到一个函数中,将其称为foo:比如
function foo()
<一些代码>
if 未预测的条件 then error() end
<一些代码>
print(a[i]) --潜在的错误:a可能不是一个table
<一些代码>
--然后使用pcall来调用foo
if pcall(foo) then
--在执行foo时没有发生错误
<常规代码>
else
--foo引发了一个错误,采取适当的行为
<错误处理代码>
end
--在lua中这个也可以匿名去处理
--比如:
if pcall(function()
<受保护的代码>
) then
<常规代码>
else
<错误处理代码>
end
8.5 错误消息与追溯
error函数 和 xpcall函数
第九章 协同程序(coroutine)
协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈,局部变量和指令指针,同时又与其他协同程序共享全局变量和其他大部分东西。从概念上讲线程与协同程序的主要区别在于:一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作地运行。就是说,一个具有多个协同程序的程序在任意时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显示的要求挂起时,他的执行才会暂停。
9.1协同程序基础
lua将所有关于协同程序的函数放在一个coroutine的table中。函数create用于创建新的协同程序。它只有一个参数,就是一个函数,用于表示新的协同程序。通常create的参数会是一个匿名函数,例如:
co=coroutine.create(function () print(“123”) end)
print(ci)–>thread
一个协同程序可以处于4种状态,挂起(suspended) 运行(running)死亡(dead)的正常(normal),刚创建的协同程序是,他处于挂起状态。也就是说,协同程序不会再创建它时自动运行其内容。可以通过函数status来检测协同程序的状态:print(coroutine.status(co))–suspended
函数coroutine.resume用于启动或者再次启动一个协同程序的执行,并将其状态由挂起改为运行。coroutine.resume(co)–hi
打印完后就死亡了 print(corountine.status(co))–dead
--协同程序真正强大在于yield函数
该函数可以让一个运行中的协同程序挂起,而之后可以再回复它运行:
co=coroutine.create(function()
for i=1,10 do
print("co",i)
coroutine.yield()
end
end)
--当唤醒这个协同程序时,他就会执行,直到第一个yield:
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
--
--参数传递
co=coroutine.create(function(a,b,c)
print("co",a,b,c)
end)
coroutine.resume(co,1,2,3)--co 1 2 3
--
--yield返回的额外值就是对应的resume传入的参数
co=coroutine.create(function()
print("co",coroutine.yield())
end)
coroutine.resume(co,3,4)--co 3 4
--
--当一个协同程序结束时,它的主函数所返回的值将作为对应的resume的返回值
--
co=coroutine.create(function()
return 6,7
end)
print(coroutine.resume(co)) -- true 6 7
Lua提供的是一种”非对称的协同程序 asymmetric coroutine” 也就是说lua提供了两个函数来了控制协同程序的执行,一个用于挂起执行,一个用于恢复执行。而其他一些语言提供了“对称的协同程序symmetric coroutine”,其中只有一个函数用于转让协同程序之间的执行权。
有人将”非对称的协同程序”称为”semo-coroutine” 还有一些人则将相同的”semo-coroutine”用于表示已某种使用受到限制的协同程序的实现。在这种实现中,一个协同程序只能在它没有调用其他函数时,才可以挂起。换句话说,只有协同程序的主函数才能调用类似于yield这样的函数。python中的“generator”正是在这种”semo-coroutine”
与协同程序之间的对称性区别相比,协同程序与generator(python)之间的区别很大,generator比较简单,无法实现某些数据结构,不过完整的协同程序却可以写出这些结构。Lua提供了完整的,非对称的协同程序。对于那些喜欢对称的协同程序的用户而言,则可以基于lua所提供的非对称功能实现出对称的协同程序,这是一个简单的额任务。
9.2管道(pipe)与过滤器(filter)
协同程序经典的示例就是“生产者-消费者”的问题,这其中涉及两个函数,一个函数不断产生值,一个不断消费这些值。比如:
function producer()
while true do
local x=io.read()--产生新的值
send(x)
end
end
--
--
function consumer()
while true do
local x=receive()
io.write(x,"\n")
end
end--这两个方法有一个问题就是谁具有主循环。
于是乎:
–消费者如下
function receive()
local status,value=coroutine.resume(producer)
return value
end
function send(x)
coroutine.yield(x)
end
–生产者如下
producer=coroutine.create(
function()
while true do
local x=io.read()
send(x)
end
end)
这样就ok了
未完待续。
9.3以协同程序实现迭代器
9.4非抢占式的(non-preemptive)
第十章
略