可 yield 的 for 循环 |
|
与其只能够编写
for msg in eachmsg() do -- handle msg end -- end of messages, clean up
你需要
repeat local msg = getmsg() if msg == nil then break end -- handle msg until false -- end of messages, clean up
然而,要使第一个代码示例工作非常简单。只需要将 `TFORLOOP` VM 操作拆分为两个操作码。第一个操作码设置一个普通的 Lua 调用,然后进入 OP_CALL 实现。接下来的操作码根据第一个操作码返回的第一个值进行条件移动和分支。
一些非常粗略的测试表明,这种改变实际上略微提高了性能,尽管结果并不确定。我想这是因为 VM 可以处理调用而无需递归,从而弥补了额外操作码的开销。
无论如何,补丁位于 [失效链接]。
(也可以在这里找到 [1],取自 Google 代码搜索缓存 [2]。)
这是一个测试程序。这里关键的函数是 `responder`,它展示了可 yield 的 `for` 循环的实际应用。测试输出紧随代码之后
local yield, resume, create, costatus = coroutine.yield, coroutine.resume, coroutine.create, coroutine.status local function input(prompt) local inf, outf = io.stdin, io.stderr return function() outf:write(prompt," ") return inf:read() end end -- These could be quite a bit more complex function eachmsg() return yield end -- This isn't actually used in this demo, but it could be :) getmsg = coroutine.yield -- This would probably be more complicated in a real app, too. function responder(name) local n = 0 print(name.." is born!") for msg in eachmsg() do n = n + 1 if msg == "goodbye" then break else print(name.." heard "..msg) end end print(name.." departs this vale of tears, after listening to "..n.." utterances") end function driver() local cmd = {} local kids = {} -- the commands we understand function cmd.quit() print "Exiting!" for _, kid in pairs(kids) do resume(kid) end return false end function cmd.kill(arg) local _, _, who = string.find(arg, "(%w+)") if not who then return "Kill who?" elseif not kids[who] then return who.."? I don't know any "..who else local status, result = resume(kids[who]) kids[who] = nil if status then return else return result end end end function cmd.spawn(arg) local _, _, who = string.find(arg, "(%w+)") if not who then return "Spawn who?" elseif kids[who] then return who .. " already exists" else kids[who] = create(responder) local status, result = resume(kids[who], who) if not status then kids[who] = nil return result end end end function cmd.list() print"Currently active:" for k in pairs(kids) do print(" "..k) end end -- main loop starts here -- for msg in input("->") do local _, _, verb, rest = string.find(msg, "%s*(%w+)%s*(.*)") if cmd[verb] then local res = cmd[verb](rest) if res then print(res) elseif res == false then return end elseif kids[verb] then local status, result = coroutine.resume(kids[verb], rest) if not status then print(verb.." exited with error "..result) kids[verb] = nil elseif coroutine.status(kids[verb]) ~= "suspended" then print(verb.." decided to go away") kids[verb] = nil end else print "I don't understand what you're talking about" end end end
示例运行
> driver() -> list Currently active: -> spawn bob bob is born! -> spawn sally sally is born! -> bob hi bob heard hi -> sally hi sally heard hi -> bob meet sally bob heard meet sally -> fred hi I don't understand what you're talking about -> spawn fred fred is born! -> list Currently active: sally fred bob -> fred how are you fred heard how are you -> fred goodbye fred departs this vale of tears, after listening to 2 utterances fred decided to go away -> kill bob bob departs this vale of tears, after listening to 2 utterances -> sally ? sally heard ? -> spawn sue sue is born! -> quit Exiting! sally departs this vale of tears, after listening to 2 utterances sue departs this vale of tears, after listening to 0 utterances
-- RiciLake