lua中交换变量的值:
遇到赋值语句 Lua会先计算右边所有的值然后再执行赋值操作,所以我们可以这样进行交换变量的值:
x, y = y, x-- swap 'x' for 'y'
a[i], a[j] = a[j], a[i]-- swap 'a[i]' for 'a[i]'
repeat-until语句:
repeat
statements; until conditions;
关于for语句
for 语句有两大类:第一,数值 for循环:
for 将用 exp3作为 step从 exp1(初始值)到exp2(终止值),执行loop-part。其中exp3可以省略,默认 step=1
有几点需要注意:
1. 三个表达式只会被计算一次,并且是在循环开始前。
for var=exp1,exp2,exp3 do loop-part
end
for i=1,f(x) do print(i)
end
for i=10,1,-1 do print(i)
end
第一个例子 f(x)只会在循环前被调用一次。
2. 控制变量 var是局部变量自动被声明,并且只在循环内有效.
如果需要保留控制变量的值,需要在循环中将其保存
for i=1,10 do print(i)
end
max = i -- probably wrong! 'i' here is global
-- find a value in a list
local found = nil for i=1,a.n do
ifa[i] == valuethen
found = i-- save value of 'i'
break
end
end
print(found)
3. 循环过程中不要改变控制变量的值,那样做的结果是不可预知的。如果要退出循
环,使用 break语句。
第二,范型 for循环:
前面已经见过一个例子:
范型 for遍历迭代子函数返回的每一个值。再看一个遍历表key 的例子:
范型 for和数值 for有两点相同:
1. 控制变量是局部变量
2. 不要修改控制变量的值再看一个例子,假定有一个表:
现在想把对应的名字转换成星期几,一个有效地解决问题的方式是构造一个反向表:
revDays = {["Sunday"] = 1, ["Monday"] = 2,["Tuesday"] = 3, ["Wednesday"] = 4,
["Thursday"] = 5, ["Friday"] = 6,
["Saturday"] = 7}下面就可以很容易获取问题的答案了:
我们不需要手工,可以自动构造反向表
如果你对范型 for还有些不清楚在后面的章节我们会继续来学习。
-- print all values of array 'a'
for i,v in ipairs(a) do print(v) end
-- print all keys of table 't'
for k in pairs(t) do
print(k)
end
days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
x = "Tuesday"
print(revDays[x])--> 3
revDays = {} for i,v in ipairs(days) do
revDays[v] = i
end
break 和 return 语句
break 语句用来退出当前循环(for,repeat,while)。在循环外部不可以使用。
return 用来从函数返回结果,当一个函数自然结束结尾会有一个默认的 return。(这种函数类似 pascal 的过程)
Lua 语法要求 break 和 return 只能出现在 block 的结尾一句(也就是说:作为 chunk的最后一句,或者在 end 之前,或者 else 前,或者 until 前),例如:
有时候为了调试或者其他目的需要在 block 的中间使用 return 或者 break,可以显式的使用 do..end 来实现:
local i = 1 while a[i] do
if a[i] == v then break end
i=i+1
end
function foo ()
return --<< SYNTAX ERROR
-- 'return' is the last statement in the next block
do return end -- OK
... -- statements not reached
end
关于函数返回多个结果值
Lua 函数可以返回多个结果值,比如 string.find,其返回匹配串“开始和结束的下标”
(如果不存在匹配串返回 nil)。
Lua 总是调整函数返回值的个数去适用调用环境,当作为一个语句调用函数时,所有返回值被忽略。假设有如下三个函数:
function foo0 () end-- returns no results function foo1 () return 'a' end-- returns 1 result
function foo2 () return 'a','b' end-- returns 2 results
第一,当作为表达式调用函数时,有以下几种情况:
1. 当调用作为表达式最后一个参数或者仅有一个参数时,根据变量个数函数尽可能
多地返回多个值,不足补 nil,超出舍去。
2. 其他情况下,函数调用仅返回第一个值(如果没有返回值为 nil)
x,y = foo2()-- x='a', y='b' x = foo2()-- x='a', 'b' is discarded x,y,z = 10,foo2()-- x=10, y='a', z='b'
x,y = foo0()-- x=nil, y=nil x,y = foo1()-- x='a', y=nil x,y,z = foo2()-- x='a', y='b', z=nil
x,y = foo2(), 20 -- x='a', y=20
x,y = foo0(), 20, 30 -- x='nil', y=20, 30 is discarded
第二,函数调用作为函数参数被调用时,和多值赋值是相同。
print(foo0())-->
print(foo1())--> a
print(foo2())-->a b
print(foo2(),1)-->a 1
print(foo2() .. "x") --> ax
第三,函数调用在表构造函数中初始化时,和多值赋值时相同。
a = {foo0()}-- a = {} (an empty table) a = {foo1()}-- a = {'a'} a = {foo2()}-- a = {'a', 'b'}a = {foo0(), foo2(), 4} -- a[1] = nil, a[2] = 'a', a[3] = 4
另外,return f()这种类型的返回 f()返回的所有值
function foo (i) if i == 0 then return foo0() elseif i == 1 then return foo1() elseif i == 2 then return foo2() end
end
print(foo(1))--> a
print(foo(2))--> a b
print(foo(0))-- (no results)
print(foo(3))-- (no results)
可以使用圆括号强制使调用返回一个值。
print((foo0()))--> nil print((foo1()))--> a print((foo2()))--> a
一个 return 语句如果使用圆括号将返回值括起来也将导致返回一个值。
函数多值返回的特殊函数 unpack,接受一个数组作为输入参数,返回数组的所有元素。unpack 被用来实现范型调用机制,在 C 语言中可以使用函数指针调用可变的函数,可以声明参数可变的函数,但不能两者同时可变。在 Lua 中如果你想调用可变参数的可变函数只需要这样:
f(unpack(a))
unpack 返回 a 所有的元素作为 f()的参数
f = string.find
a = {"hello", "ll"}print(f(unpack(a))) --> 3 4
预定义的 unpack 函数是用 C 语言实现的,我们也可以用 Lua 来完成:
function unpack(t, i) i = i or 1
if t[i] then return t[i], unpack(t, i + 1)
endend
可变参数
Lua 函数可以接受可变数目的参数,和 C 语言类似在函数参数列表中使用三点(...)表示函数有可变的参数。Lua 将函数的参数放在一个叫 arg 的表中,除了参数以外,arg表中还有一个域 n 表示参数的个数。
例如,我们可以重写 print 函数:
printResult = ""
function print(...) for i,v in ipairs(arg) do
printResult = printResult .. tostring(v) .. "\t" end
printResult = printResult .. "\n" end
有时候我们可能需要几个固定参数加上可变参数
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}
举个具体的例子,如果我们只想要 string.find 返回的第二个值:
一个典型的方法是使用虚变量(下划线)
local _, x = string.find(s, p) -- now use `x' ...
还可以利用可变参数声明一个 select 函数:
function select (n, ...)
return arg[n]
end
print(string.find("hello hello", " hel")) --> 6 9
print(select(1, string.find("hello hello", " hel"))) --> 6
print(select(2, string.find("hello hello", " hel"))) --> 9
有时候需要将函数的可变参数传递给另外的函数调用,可以使用前面我们说过的unpack(arg)返回 arg 表所有的可变参数,Lua 提供了一个文本格式化的函数 string.format(类似 C 语言的 sprintf 函数):
function fwrite(fmt, ...) return io.write(string.format(fmt, unpack(arg)))
end
这个例子将文本格式化操作和写操作组合为一个函数。
命名参数
Lua 的函数参数是和位置相关的,调用时实参会按顺序依次传给形参。有时候用名字指定参数是很有用的,比如 rename 函数用来给一个文件重命名,有时候我们我们记不清命名前后两个参数的顺序了:
-- invalid code
rename(old="temp.lua", new="temp1.lua")上面这段代码是无效的,Lua 可以通过将所有的参数放在一个表中,把表作为函数的唯一参数来实现上面这段伪代码的功能。因为 Lua 语法支持函数调用时实参可以是表的构造。
根据这个想法我们重定义了 rename:
function rename (arg) return os.rename(arg.old, arg.new)end
lua函数
Lua 中的函数是带有词法定界(lexical scoping)的第一类值(first-class values)。
第一类值指:在 Lua 中函数和其他值(数值、字符串)一样,函数可以被存放在变量中,也可以存放在表中,可以作为函数的参数,还可以作为函数的返回值。
词法定界指:被嵌套的函数可以访问他外部函数中的变量。这一特性给 Lua 提供了强大的编程能力。
闭包
当一个函数内部嵌套另一个函数定义时,内部的函数体可以访问外部的函数的局部 变量,这种特征我们称作词法定界。虽然这看起来很清楚,事实并非如此,词法定界加 上第一类函数在编程语言里是一个功能强大的概念,很少语言提供这种支持。
下面看一个简单的例子,假定有一个学生姓名的列表和一个学生名和成绩对应的表;现在想根据学生的成绩从高到低对学生进行排序,可以这样做:
names = {"Peter", "Paul", "Mary"} grades = {Mary = 10, Paul = 7, Peter = 8} table.sort(names, function (n1, n2)return grades[n1] > grades[n2] -- compare the grades
end)
假定创建一个函数实现此功能:
function sortbygrade (names, grades) table.sort(names, function (n1, n2)return grades[n1] > grades[n2] -- compare the gradesend)
end
例子中包含在 sortbygrade 函数内部的 sort 中的匿名函数可以访问 sortbygrade 的参数grades,在匿名函数内部 grades 不是全局变量也不是局部变量,我们称作外部的局部变量(external local variable)或者 upvalue。(upvalue 意思有些误导,然而在 Lua 中他的存在有历史的根源,还有他比起 external local variable 简短)。
看下面的代码:
function newCounter() local i = 0return function()
i=i+1
return i
end
end
c1 = newCounter()
print(c1()) --> 1
print(c1()) --> 2
正确的尾调用(Proper Tail Calls)
尾调用是一种类似在函数结尾的 goto 调用,当函数最后一个动作是调用另外一个函数时,我们称这种调用尾调用。
function f(x) return g(x)end
g 的调用是尾调用。