初识Lua
前几天为了用xLua,学习了Lua语言,算是能用了...吧?(其实就只是跟着菜鸟教程过了一遍....)。但是感觉自己的记性一天不如一天(Orz),还是写个笔记好了,可能会对比着C++来。欢迎批评指正或者补充~
一.基础(几乎语言都有的东西)
1. 数据类型
Lua的数据类型很少,只有8种: nil、boolean、number、string、userdata、function、thread、table。
nil 和C++里的 NULL 比较像,不过要注意的是,type(nil)~=nil 因为type()函数返回的是string。
string 可以用 " ", ' ', [[ ]] 来包裹。其中[[ ]]一般包裹一整块的字符串。
userdata 一般存储C/C++数据。
function 用...来表示可变长参数,并且可以返回多个值。
thread 我也只看了协程部分,见下文。
table 是一个有点想法的数据结构。其组成是一个数组和一个hash表(我都想要.jpg)。数组的扩张方法是*2(也就是说capacity永远是2^n)。
2.语法词法
特殊的算术运算符和关系运算符:幂运算是 ^ ,不等于是 ~= 。
逻辑运算符:and,or,not
长度运算符:# ,把它放在table或者string的前面,可以返回length。.. ,可以连接不同的字符串。
除了 ^ 和 .. 外所有的二元运算符都是左连接的。
if 语法和C++差不多,多了个then而已。
1 if( 布尔表达式 1) 2 then 3 --[ 语句块 --] 4 elseif( 布尔表达式 2) 5 then 6 --[ 语句块 --] 7 else 8 --[ 语句块 --] 9 end
循环就有讲究了,分别为while,for,repeat三种
1 while(condition) 2 do 3 statements 4 end 5 6 for var=from,to,step do 7 statements 8 end 9 for i, v in ipairs(a) do 10 statements 11 end 12 13 repeat 14 statements 15 until( condition )
可以看到,其实while和repeat不过是一个在前一个在后,可以归为一种。for循环第一种就是普通用一个number(必须是number)作为控制变量进行循环,第二种则是用迭代器(见下文)进行循环。但是这个for循环很有意思,他是先判定循环几次,然后只运行那么多次的statements。也就是说像
1 for i=1,10,1 do 2 i=i-2 3 end
这种并不是死循环。
二.特性(开始说一些特别的东西)
1.迭代器
lua里的迭代器实际上是三个变量:迭代函数,不变量,控制变量。像ipairs这种官方提供的函数也不过是包裹一下,返回这三个值而已。对于迭代函数来说,它需要返回两个值:控制变量新的值 和 迭代出来的值(也就是我们实际获得的)。一旦有一次没有return,则停止迭代(待验证)。如:
function iter(arg, index) index = index + 1 print("index:", index) local v = arg[index] if(v and v~=100) then return index,v end end function foo(arg) for i,n in iter,arg,0 do print(n) end end local a = {["h"]=50, 20, 150, 100, 1566, [20]=6} foo(a)
结果为
index: 1 20 index: 2 150 index: 3
2.元表
由于元表这个东西不实际用,理解会很肤浅(没错就是我),大家将就着看吧......
一个表可以有另一个表作为它的元表。我的理解是,表本身用作数据存放,元表则作为数据补充和方法实现。(所以可以把元表近似看作表本身的父表)
表本身用作数据存放自不必说,而元表则作为数据补充体现在:若读写表本身时,表里没有其读写数据,则调用元表key为__index(读)和__newindex(写)的键值或函数。而方法实现体现在:
运算符重载: key 对应运算符 __add + __sub - __mul * __div / __mod % __unm - __concat .. __eq == __lt < __le <=
除了运算符重载(虽然不准确但就喜欢这么叫)外,还有__call和__tostring。前者在 Lua 调用一个值时调用,后者不多说。
3.协程
lua中每个协程都在一个单独的线程里。协程只有几个函数
coroutine.create() 创建协程,返回thread对象,使用resume以重新执行协程 coroutine.resume() 重新执行协程 coroutine.yield() 挂起 coroutine.status() 查看状态(dead,suspended,running) coroutine.wrap() 创建协程,返回function对象,调用函数为重新执行协程,其实质是非保护模式下的resume coroutine.running() 返回线程ID
值得注意的,一个是create和wrap的区别,见上述。一个是yield和resume的配合。如:
co = coroutine.create( function(a) print(a,"a[1]=",a[1]) m = coroutine.yield(a) print(m,"m[1]=",m[1]) m = coroutine.yield(m) print(m,"m[1]=",m[1]) return a end ) co2 = coroutine.create( function() print("co2", coroutine.running()) end ) f, c = coroutine.resume(co,{3,6}) print(c,"c[1]=",c[1]) s, c1 = coroutine.resume(co, {5,5}) print(c,"c[1]=",c[1]) print(c1,"c1[1]=",c1[1]) coroutine.resume(co,{6,6}) coroutine.resume(co)
其结果为:
table: 00559CA0 a[1]= 3 table: 00559CA0 c[1]= 3 table: 00559BD8 m[1]= 5 table: 00559CA0 c[1]= 3 table: 00559BD8 c1[1]= 5 table: 00559D68 m[1]= 6
由此可以看出:
1. 首次调用resume执行协程co时,参数 会赋值给协程的函数,作为函数参数 2. yeild的参数会作为resume的第二个返回值(第一个是boolean表示是否成功) 3. 再调用resume执行协程co时,参数 会赋值给协程上一次yield的返回值 4. 循环2、3直到return
4.垃圾回收
这就没细看了,就列个表以后忘了回来查吧。
collectgarbage("collect"): 做一次完整的垃圾收集循环。通过参数 opt 它提供了一组不同的功能: collectgarbage("count"):以 K 字节数为单位返回 Lua 使用的总内存数.这个值有小数部分,所以只需要乘上1024就能得到Lua使用的准确字节数(除非溢出) collectgarbage("restart"): 重启垃圾收集器的自动运行。 collectgarbage("setpause"): 将 arg 设为收集器的 间歇率。 返回 间歇率 的前一个值。 collectgarbage("setstepmul"): 返回 步进倍率 的前一个值。 collectgarbage("step"): 单步运行垃圾收集器。 步长"大小"由arg控制。传入0时,收集器步进(不可分割的)一步。传入非0值,收集器收集相当于Lua分配这些多(K字节内存的工作。如果收集器结束一个循环将返回true 。 collectgarbage("stop"): 停止垃圾收集器的运行。 在调用重启前,收集器只会因显式的调用运行。
5.其他(写一些杂七杂八)
: 和 . 的区别:table:function(args...)是一个语法糖, 其实质为table.function(self,args...)并自动传参self。