- 赋值
- 局部变量与块
- 控制结构
- break和return
Lua支持的常规语句基本与C或Pascal中所支持的语句相似,它们包括赋值、控制结构、过程调用。另外Lua还支持非传统的语句,例如多重赋值(multiple assignment)和局部变量声明。
赋值语句
赋值(assignment)的基本含义是修改一个变量或一个table
中字段的值。赋值时改变一个变量的值和标域的基本方式。
str = "hello" .. " world"
print(str) -- hello world
Lua允许“多重赋值”,也就是一次性将多个值赋给多个变量,即对多个变量同时赋值,变量列表和值列表的各个元素使用逗号分隔,赋值语句右边的值会依次赋予给左边的变量。
x, y = 10, 2 * math.pi
print(x, y) -- 10 6.2831853071796
多重赋值中,Lua先对=
右边元素求值,然后才执行赋值。这样便可以用一句多重赋值来交换两个变量。
x, y = 1, 2
x, y = y, x
print(x,y) -- 2 1
Lua会将=
右边值的个数调整到与左边变量的个数相一致,规则是:
- 变量个数>值的个数:按变量个数补足
nil
- 变量个数<值的个数:多余的值会被忽略(“静悄悄的”丢弃掉)
x, y, z = 0, 1
print(x, y, z) -- 0 1 nil
x, y = x + 1, y + 1, y + 2
print(x,y) -- 1 2
x, y, z = 0
print(x,y,z) -- 0 nil nil
多重赋值并不会比相等价的多条单一变量赋值语句更快,但有时的确会需要多重赋值。
多重赋值经常用来交换变量(swap)或将函数调用返回给变量。
x, y = fn()
局部变量与代码块(block)
局部变量
相对于全局变量,Lua提供了局部变量,通过local
语句来创建局部变量。
i = 10 -- 全局变量
local j = 100 -- 局部变量
代码块
与全局变量不同的是,局部变量的作用域仅限于声明它们的那个代码块。代码块(block)是一个控制结构的执行体、或是一个函数的执行体、亦或是一个程序块(chunk)。
x = 3
local y = 1 -- 程序块中的局部变量
while y <= x do
local x = y * 2 -- while循环体中的局部变量
print(x) -- 2 4 6
y = y + 1
end
交互模式下输入下列代码可能不会如预期那样工作,因为交互模式中每行输入内容自身就形成了一个程序块(chunk)。
i = 3;
if i > 20 then
local x -- then中的局部变量
x = 10
print(x)
else
print(x) -- nil
end
为了这个问题,可显式的界定一个块(block),只需要将内容放入一对关键字do-end
中即可,相当于C/C++中的{}
。每当输入do
时,Lua就不会单独地执行后面每行的内容,而是直至遇到相应的end
时,才会执行整个块的内容。
do
local x = 2 * a
local y = (b ^ 2 - 4 * a * c) ^ (1 / 2)
m = (-b + y) / x;
n = (-b - y) / x;
end
尽可能地使用局部变量,这是一种良好的编程风格,局部变量可避免一些无用的名称引入全局环境(global environment),避免搞乱了全局环境。访问局部变量比访问全局变量更快。局部变量会随着其作用域的结束而消失,这样便使垃圾收集器可以释放其值。
- 避免命名冲突
- 访问局部变量的速度比全局变量更快
给代码块block
划定一个明确的界限do..end
内的部分,当想更好的控制局部变量的作用范围时很有用。
do
local x = x*2
local y = sqrt(a^2 - 4*a*c)
end
print(x, yu)
Lua将局部变量的声明当做语句来处理。因此可以在任何书写语句的地方书写局部变量的声明。所声明的局部变量的作用域从声明语句开始,直至所在块的结尾。
local x, y = 1, 10
if x < y then
print(x) -- 1
local x
print(x) -- nil
end
print(x,y)--1 10
声明语句中还可包含初始化赋值,其规则和普通的赋值语句完全一样:额外的值会被丢弃,额外的变量会被赋予nil
。如果一条声明语句没有初始化赋值,那么 它声明的所有变量都会初始化为nil
。
Lua中有在种习惯性写法为local foo = foo
,这句代码创建一个局部变量foo
,并将用全局变量foo
的值初始化它。如果后续其他函数改变了全局foo
的值,那么可以在这里先将它的值保存起来。这种方式还可以加速在当前作用域中对foo
的访问。
在需要时才声明变量,可以使这个变量在初始化时刻就拥有一个有意义的初值。此外,缩短变量的作用域有助于提高代码的可读性。
控制结构
控制结构的条件表达式可以是任何值,Lua认为false
和nil
为假。
- Lua提供一组传统的、小巧的控制结构,包括用于条件执行的
if
,用于迭代的while
、repeat
、for
。 - 控制结构均有 一个显式的终止符:
if、for、while
以end
作为结尾,repeat
以until
作为结尾。 - 控制结构中的条件表达式可以是任意值,Lua将所有不是
false
和nil
的值视为真。
判断语句
Lua中判断语句包括三个关键字if
、else
、elseif
,并以end
作为结束整个语句的标识。
判断语句的格式分为三种:
第1种格式
if 表达式 then
语句块
end
第2种格式
if 表达式 then
为真语句块
else
为假语句块
end
第3种格式
if 表达式1 then
语句块1
elseif 表达式2 then
语句块2
elseif 表达式3 then
语句块3
...
else
语句块n
end
运算符与组块
local today=1
if today==1 then
print('Monday')
elseif today==2 then
print('Tuesday')
elseif today==3 then
print('Wednesday')
elseif today==4 then
print('Thursday')
elseif today==5 then
print('Friday')
elseif today==6 then
print('Saturday')
elseif today==7 or today==0 then
print('Sunday')
else
print('Unknown')
end
-- Monday
判断考试单科成绩在90和100之间为优秀,70到90之间为良好,60到70之间为及格,0到60之间为不及格。
local n=0
if n>=90 and n<=100 then
print('excellent/great/best')
elseif n>=70 and n<90 then
print('good')
elseif n>=60 and n<70 then
print('average/general')
elseif n>=0 and n<60 then
print('bad/weak/poor')
else
print('error')
end
判断一个数是否为大于100的偶数
local n=0
if n<100 and n%2==0 then
print('success')
else
print('error')
end
判断两个数是否均为小于或等于200的奇数
local n,m=0,1
if n<=200 and m<=200 and n%2==1 and m%2==1 then
print('success')
else
print('error')
end
if then else
if a<0 then a=0 end
if a<0 then return a else return b end
if line>MAXLINES then
showpage()
line=0
end
若要编写嵌套的if
可使用elseif
,它类似于在else
后紧跟一个if
,它还可以避免在这样的嵌套中出现多个end
。
if op=='+' then
result = a+b
elseif op=='-' then
result = a-b
elseif op=='*' then
result = a*b
elseif op=='/' then
result = a/b
else
error('invalid operation')
end
Lua不支持switch
语句,一连串的if-else if
代码是很常见的。
循环结构
while
arr = {'x','y','z'} -- Lua中数组的索引从1开始
local idx = 1
while arr[idx] do
print(idx, arr[idx])
idx = idx + 1 -- Lua中没有自增自减操作
end
-[[
1 x
2 y
3 z
-]]
repeat
repeat
line = io.read()
until line ~= ""
print(line)
repeat...until
相当于while...do
local sum = 1
repeat
sum = sum + 1
print(sum)
until sum == 10
for
-- for循环默认步进值为1
for idx=1,10,2 do
print(idx) -- 1 3 5 7 9
end
arr = {'x','y','z'}
for i=1,#arr do -- #arr表示arr的长度
print(i, arr[i])
end
循环语句
循环语句是程序中一种重要的控制结构,特点是在给定条件成立时,反复执行某程序段,知道条件不成立为止。给定的条件为循环条件,反复执行的程序段称为循环体。Lua中主要的循环语句分为:
循环语句1:while...do
while 循环条件 do
循环体
end
while循环线判断循环条件表达式后执行,若表达式为假,则不运行循环直接跳出。
示例:
local i=5
while i>0 do
print(i)
i = i-1
end
输出1到100之间能被7整除的数字
local n=1
while n<100 do
if n%7==0 then
print(n)
end
n = n + 1
end
Lua先测试while循环的条件,为假则循环结束,否则执行循环体,并重复此过程。
local i=1
local arr = {1,2,3,4,5}
while arr[i] do
print(arr[i])
i = i+1
end
循环语句2:repeat...until
repeat
循环体
until 循环条件
repeat是先运行一遍循环体,然后在判断循环条件表达式。
定义函数利用循环让函数能够计算n的阶乘
fn = function(n)
local m = 1
if n < 1 then
n = 1
end
repeat
m = n * m
n = n - 1
until n == 0
print(n, m)
end
fn(3)
一条repeat-until
语句重复执行其循环体直至条件为真时结束,测试是在循环体之后做的,因此循环体至少会执行一次。
repeat
line = io.read()
until line~=""
print(line)
在Lua中一个声明在循环体中的局部变量的作用域包括了条件测试。
local sqr = x/2
repeat
sqr=(sqr+x/sqr)/2
local error=math.abs(sqr^2-x)
until error
for
循环语句分为两种:一种是数值for
,另一种是泛型for
。
循环语句3:for...do
for 变量=初始值,终止值,步长 do
循环体
end
步长可以省略,默认值为1。
for i = 10, 1, -1 do
print(i)
end
初始值、终止值、步长三部分都只会被执行一次,即使使用变量或表达式替代终止值和步长,在循环体中改变了终止值和步长,循环也能正常结束。
stop, step = 10, 1
for start = 1, stop, step do
stop = stop + 1
step = step + 1
print(start, stop, step)
end
执行循环时若想让循环中途停止不再执行,应该怎么办呢?使用break
关键字,它的作用就是跳出正在执行的循环,注意break
只能在循环体中使用。
stop, step = 10, 1
for start = 1, stop, step do
if start == 5 then
break
end
print(start, stop, step)
end
循环语句4:for...in...do
数字型for(numeric for)
for语句有两种形式:数字型for(numeric for)、泛型for(generic for)
数字型for的语法:
for var=begin,end,step do
end
--[[
var 从begin表达式变化到end表达式,每次变化都以step作为步长递增var,并执行一次执行体。
若不指定step步长,则默认为1.
--]]
示例:九九乘法表
1x1=01 1x2=02 1x3=03 1x4=04 1x5=05 1x6=06 1x7=07 1x8=08 1x9=09
2x2=04 2x3=06 2x4=08 2x5=10 2x6=12 2x7=14 2x8=16 2x9=18
3x3=09 3x4=12 3x5=15 3x6=18 3x7=21 3x8=24 3x9=27
4x4=16 4x5=20 4x6=24 4x7=28 4x8=32 4x9=36
5x5=25 5x6=30 5x7=35 5x8=40 5x9=45
6x6=36 6x7=42 6x8=48 6x9=54
7x7=49 7x8=56 7x9=63
8x8=64 8x9=72
9x9=81
for i=1,9,1 do
local str = ""
for j=1,9,1 do
if(j>=i) then
local result = i*j
if result<=9 then
result = "0"..result
end
str = str..i.."x"..j.."="..result.." "
end
end
print(str)
end
示例
for i=1,f(x) do
print(i)
end
for i=10,1,-1 do
print(i)
end
如果不想给循环设置上限的话,可使用常量math.huge
。
for i=1,math.huge do
if (0.3*i^3 - 20*i^2 - 500 >= 0) then
print(i)
break
end
end
在编程语言中,循环与判断的应用是非常广泛的,Lua中循环判断语句是允许嵌套使用,用来处理一些比较复杂的问题。
使用1,2,3,4四个数字组成互不相同且无重复的三位数,三位数可填写在百位、十位、个位,可先组成排列后在去除不满足条件的排列。
for a = 1, 4, 1 do
for b = 1, 4, 1 do
for c = 1, 4, 1 do
if a ~= b and a ~= c and b ~= c then
print(a..b..c)
end
end
end
end
计算斐波那契数列的前20个数字,斐波那契数列又称为黄金分割数列,是这样的一个数列1,1,2,3,5,8,13,21...
fb = function(i)
if i > 0 and i <= 2 then
return 1
else
local j = fb(i - 1) + fb(i - 2)
return j
end
end
n = 1
while n < 10 do
print(fb(n))
n = n + 1
end
递归,从前有座山山里有座庙,庙里有个老和尚正在讲故事:从前有座山,山里有座庙...直到有一天有个老和尚不再讲故事了,于是他去找到之前那个讲故事的那个老和尚,直到找到最初讲故事的那个老和尚。
泛型for
常见迭代器
- 迭代数组的
ipairs
- 迭代
table
表的pairs
- 迭代文件每行的
lines
-- 循环遍历数组
for k,v in ipairs(arr) do
print(k, v)
end
-- 循环遍历表
for item in pairs(tbl) do
print(item)
end
break和return语句
-
break
语句用来退出当前循环(for
、repeat
、while
),在循环外部不可以使用。 -
return
语句用来从函数返回结果,当一个函数自然结束,结尾会有一个默认的return
,这种函数类似pascal的过程。
Lua语法要求break
和return
只能出现在代码块block
的结尾一句,也就是说,作为程序快chunk
的最后一句,或在end
之前,或在else
前,或在until
前。