lua环境
lua环境由所有可操作的数据构成。
如编译好的函数,变量以及其他运行时内存。
这些数据保存在一个称作lua_State的结构中。所有lua应用程序都要求至少有一个lua_State。
如果需要还可多个(如需要为两个不同的系统保存不同的数据时)。
Lua环境是用来发送和接受数据的地方,它利用栈来达到该目的。
Lua栈不同于系统栈,它只能通过Lua的API函数访问。
元表
Lua中得每个值都有一套预定义的操作集合。即一个元表。
table和userdata可以有各自独立的元表,而其他类型的值则共享其类型所属的单一元表。
lua在创建新的table时不会创建元表.
t = {}
print(getmetatable(t)) — > nil
--可以使用setmetatable来设置或修改任何table的元表
t1 = {}
setmetatable(t,t1)
可以通过元表来修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定的操作。
假设a和b都是table,通过元表可以定义如何计算a+b。当lua试图将2个table相加时,会先检查两者之一是否有元表,然后检查该元表中是否有一个_add的字段。如果lua找到了该字段,就调用该字段对应的值。
任何table都可以作为任何值的元表,而一组相关的table也可以共享一个通用的元表,这个元表描述了它们共同的行为。一个table甚至可以作为它自己的元表,用于描述其特有的行为。
lua中只能设置table的元表。若要设置其他类型的值的元表,则必须通过c代码来完成。
元方法
当访问一个table中不存在的字段时,会促使解释器去查找一个叫__index的元方法。由这个元方法提供最终结果。
Window = {}
Window.mt = {}
--构造函数
function Window.new(0)
—元表
setmetatable(o,window.mt)
return o
end
Window.prototype = {x=0,y=0,width=100,height=100}
Window.t.__index = function(table.key)
return Window.prototype[key]
end
--等价于
Window.t.__index = Window.prototype
w = Window.new(x=10,y=20)
print(w.width) —>100
当lua检测到w中没有某字段,而其元表中却有一个__index字段,那么lua就会以w来调用这个__index元方法。随后元方法用这个key来索引原型table
__index元方法不必一定是一个函数,还可以是一个table。
当它使一个函数时,lua以table和不存在的key座位参数来调用该函数,而当它是一个table时,lua就以相同的方式来重新访问这个table。
调用rawget(t,i)就是对table t进行了一个 原始的raw 访问,不考虑元表。
__index用于table的更新,而__newindex用于table的查询。
当一个table中不存在的索引赋值时,解释器就会查找__newindex元方法。如果有这个元方法,解释器就调用它,而不是执行赋值。如果这个元方法是一个table,解释器就在这个table中执行赋值,而不是对原来的table。
调用rewset就可以绕过元方法。
模块 包
一个模块就是一个程序库,可以通过require来加载,然后得到一个全局变量,表示一个table。这个table就像是一个名称空间,其内容就是模块中导出的所有东西,如函数和常量。
如果模块已经加载,就返回相应的值
加载模块
1. 首先通过package.loaded判断该模块是否已经存在
2. 通过package.preload判断preload是否存在,
3. 通过package.path查找lua文件
4. 通过package.cpath查找c库
5. 以第一个”.”为分割,将模块名划分为:(main, sub)的形式,根据package.cpath查找
6. 通过loadfile来加载该文件,如果是c程序库,就通过loadlib来加载
7. 只有第一次加载时会执行(要每次都执行可以使用loadfile)
--判断是否加载
local isLoaded = package.loaded[filename]
--重新加载 例如热更新
package.loaded['foo'] = nil
require "foo"
局部变量
尽可能使用局部变量,
1. 加快访问速度
2. 避免将一些无用的名称引用全局变量,搞乱了全局变量
创建局部变量来保存全局变量
local foo = foo
如果后续其他函数改变了全局变量foo的值,也可以起到临时保存的作用
错误处理
手动抛出错误
error("")
断言
assert(name == “a”,”error”)
类似try catch
local status,err = pcall(test)
if status then
--正常
else
--异常
end
闭合函数
一个函数加上改函数所需访问的所有非局部变量
function count()
int i = 1;
return function()
i = i + 1
return i
end
end
尾调用
一个函数的调用是另一个函数的最后一个动作时,这个调用就称之为尾调用。
function mute()
return count() //是
return count() + 1// 不是
end
有点,不会销毁多余的栈空间
杂记
如果你想删除一个全局变量,只需要将变量赋值为nil
控制结构的条件中除了false和nil为假,其他值都为真。所以Lua认为0和空串都是真。
lua执行的每段代码,例如一个源代码文件或在交互模式中输入的一行代码,都成为一个程序块