- Lua的局部变量的作用域从声明位置开始到所在语句块结束。
- 对于表t,t['idx'] 等价于 t.idx,需要注意的是,t[idx]跟前面两者不一样。
冒号 vs 点号
函数定义
a:fun()等价于a.fun(self)
a:fun(var)等价于a.fun(self, var)
使用冒号定义时参数列表里第一个参数为隐藏的self。
函数调用
a:fun()等价于a.fun(self = a)
a:fun(var)等价于a.fun(self = a, var)
使用冒号进行调用时参数列表里第一个参数为隐藏的self,且self的值默认为调用者自身。
闭包
闭包,即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。也就是说,内部函数有可能在外部函数返回后被执行。而当这个内部函数执行时,它仍然必需访问其外部函数的局部变量、参数以及其他内部函数。这些局部变量、参数和函数声明(最初时)的值是外部函数返回时的值,但也会受到内部函数的影响。
元表
通常,Lua中的每个值都有一套预定义的操作集合。例如,可以将数字相加,可以连接字符串,还可以在table中插入一对key-value等。但我们无法将两个table相加,无法对函数作比较,也无法调用一个字符串。可以通过元表(metatable)来修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定的操作。
mytable = {} -- 普通表
mymetatable = {} -- 元表
setmetatable(mytable, mymetatable)
-- 等价于
mytable = setmetatable({}, {})
-- 返回对象元表
getmetatable(mytable)
例如,假设a和b都是table,通过元表可以定义如何计算表达式a+b。当Lua试图将两个table相加时,它会先检查两者之一是否有元表,然后检查该元表中是否有一个叫__add的字段。如果Lua找到了该字段,就调用该字段对应的值。这个值也就是所谓的元方法(metamethod),它应该是一个函数。
例如,__index元方法,Lua查找一个表元素时的规则,其实就是如下3个步骤:
- 在表中查找,如果找到,返回该元素,找不到则继续
- 判断该表是否有元表,如果没有返回nil,有则继续
- 判断元表是否有__index方法,如果__index方法为nil,返回nil;如果__index方法是一个表,重复1、2、3步;如果__index方法是一个函数,则返回该函数的返回值
在Lua代码中,只能设置table的元表;若要设置其它类型的值的元表,则必须通过C代码来完成。
元表还可以指定关系操作符的含义,元方法为__eq(等于)、__lt(小于)和__le(小于等于)。而其它3个关系操作符则没有单独的元方法,Lua会将a~=b转化为not(a==b),将a>b转化为b<a,将a>=b转化为b<=a。
__add | + |
__sub | - |
__mul | * |
__div | / |
__mod | % |
__unm | -(取反,一元操作符) |
__concat | .. |
__eq | == |
__lt | < |
__le | <= |
Lua中的table就是一种对象,这句话可以从3个方面来证实:
- table与对象一样可以拥有状态
- table也与对象一样拥有一个独立于其值的标识(一个self),使用self参数是所有面向对象语言的一个核心。大多数对象语言都能对程序员隐藏部分self参数,从而使得程序员不必显示地声明这个参数。Lua只需要使用冒号,就能隐藏该参数。使用一个额外的参数(self或this)表示“接受者”,指定一项操作作用于它,可使对象拥有独立的生命周期。
- table与对象一样具有独立于创建者和创建地的生命周期
对象有了一个标识、一个状态和状态之上的操作,还需要一个类(class)系统、继承和私密性(privacy)。
tolua#
- 在CustomSetting.cs中添加需要导出的类或者委托,之后点击菜单Lua->Generate All
- Generate后可以在Lua直接调用上述的类或者委托
- tolua.lua: cannot load incompatible bytecode(Hunger: 打安卓包(32位)通过Unity编辑器(默认64位)启动游戏会报错,重新打win64的包可解决。)
参考资料:
《Lua程序设计(第2版)》
【Unity游戏开发】Lua中的os.date和os.time函数