lua学习笔记

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作为 stepexp1(初始值)到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 = 0

return 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 的调用是尾调用。


 
           


你可能感兴趣的:(lua学习笔记)