For 教程 |
|
for 语句有两种不同的形式。一种用于迭代数值序列,另一种用于迭代通过函数调用的迭代器。for 语句在《参考手册》的 2.4.5 节中进行了介绍。[1]
数值序列版本的 for 语句的语法如下:
for 变量 = 起始值表达式 , 结束值表达式 [, 步长表达式] do 块 end该语句在进入 for 块之前,将变量设置为起始值表达式的值。只有当变量尚未超过结束值表达式所表示的最后一个值时,才会进入该块。这包括第一次迭代循环。每次退出块时,步长表达式的值会被加到变量上。指定步长表达式是可选的。如果未指定,则使用值 1。例如:
> for i = 1,3 do print(i) end -- count from 1 to 3 1 2 3 > for i = 3,1 do print(i) end -- count from 3 to 1 in steps of 1. zero iterations! > for i = 3,1,-1 do print(i) end -- count down from 3 to 1 3 2 1 > for i=1,0,-0.25 do print(i) end -- we're not limited to integers 1 0.75 0.5 0.25 0
i 的作用域将限定在 for 循环的作用域内。即:> print(i) -- after the above code nil
for v = e1, e2, e3 do block end 等价于以下 Lua 代码:
do local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3) if not (var and limit and step) then error() end while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do local v = var block var = var + step end end
第二种形式的 for 循环语法如下:
for 变量 {, 变量} in 表达式列表 do 块 end表达式列表在进入循环之前被评估一次。其结果是一个迭代器函数(它设置变量的值)、一个状态(从中可以读取值)和一个初始值(用于开始迭代)。
Lua 提供了一个 pairs() 函数来为我们创建用于迭代表的表达式列表。pairs() 函数允许迭代键值对。请注意,返回项的顺序未定义,即使对于索引表也是如此。
> for key,value in pairs(t) do print(key,value) end 3 10 1 3 4 17 2 7 pi 3.14159 banana yellow
ipairs() 函数允许迭代索引值对。这些是键值对,其中键是数组的索引。返回元素的顺序保证是索引的数值顺序,非整数键将被跳过。使用上面示例中的同一个表:
> for index,value in ipairs(t) do print(index,value) end 1 3 2 7 3 10 4 17
next(table [,index]) 函数有助于迭代表。当给定一个表和一个索引时,它会返回表中的下一个键值对,例如:
> = next(t) -- index will be nil, the beginning 1 3 > = next(t,4) pi 3.14159
与 pairs() 一样,返回项的顺序未定义;索引键可以按任意顺序返回,不只是递增的数值顺序。pairs() 函数返回一个包含 next() 的表达式列表,因此我们可以迭代表。我们可以如下所示将自己的表达式列表传递给 for 语句:
> for key,value in next,t,nil do print(key,value) end 1 3 2 7 3 10 4 17 pi 3.14159 banana yellow
next, table, nil 作为表达式列表传递给 for 语句。我们在这里表示,我们想使用迭代器函数 next(),作用于表 t,从 nil(开始)开始。for 语句会一直执行,直到 next() 函数返回 nil(表结束)。
Lua 在 io 库中提供了其他有用的迭代器,例如 io.lines([filename])。我们可以通过创建一个包含几行文本的自定义文件来演示这一点。
> io.output(io.open("my.txt","w")) > io.write("This is\nsome sample text\nfor Lua.") > io.close()
io.lines 迭代器来读取它:> for line in io.lines("my.txt") do print(line) end This is some sample text for Lua.
io 库提供了另一种迭代文本文件行的方法。
> file = assert(io.open("my.txt", "r")) > for line in file:lines() do print(line) end This is some sample text for Lua. > file:close()
与 io.lines() 的区别是什么?
您需要显式地打开和关闭文件。这的一个优点是,如果文件无法打开,您可以优雅地处理这种失败。在这里,assert 的效果与 io.lines 相同:解释器会停止并显示指向错误行的错误消息;但是您可以测试 file 是否为 nil 值并执行其他操作。
另一个优点是您可以从任何一行开始循环:
file = assert(io.open("list.txt", "r")) local line = file:read() if string.sub(line, 1, 1) ~= '#' then ProcessLine(line) -- File doesn't start with a comment, process the first line end -- We could also loop on the first lines, while they are comment -- Process the remainder of the file for line in file:lines() do ProcessLine(line) end file:close()
我们可以编写自己的迭代器,类似于 next(),来迭代任何数据序列。这在 IteratorsTutorial 中有更详细的介绍。