Unity中的Lua
</div>
<p>结合以前的初步学习了解,这一次要对Lua进行进一步的深入学习。</p>
首先我们要知道Lua是脚本语言,是有自己的虚拟机,是解析执行而非像C#,C++,Java这些编译执行。同时Lua是弱类型语言。
这里不更多的讲解Lua虚拟机相关概念,详情参考http://blog.sina.com.cn/s/blog_8c7d49f20102uzsx.html
这里只要知道Lua的虚拟机(程序模拟线程,堆栈等)是运行在程序里而非物理CPU上,因此只要虚拟机把Lua脚本解析成对应平台的机器码就能支持跨平台(好比Java的JVM)。
Lua Study
以前的部分学习参考:
Scripting System & Lua Study
Lua — some important concept and knowledge
Lua - C API
Lua - C call Lua & Lua call C
Lua - Object Oriented Programming
Lua - Userdata
Lua - Managing Resources & Threads and States
Weak Tables And Finalizers
“and Finalizers Lua does automatic memory management. Programs create objects (tables, threads, etc.), but there is no function to delete objects. Lua automatically deletes objects that become garbage, using garbage collection. “
Weak Table
“Weak tables allow the collection of Lua objects that are still accessible to the program”
“A weak reference is a reference to an object hat is not considered by the garbage collector”
“In weak tables,, both keys and values can be weak”(three kinds of week table:1. weak key 2. weak value 3. weak key and value)
Weak Table Using:
- 释放使用不再使用的缓存数据(memorizing)
Auxiliary table(辅助表),Lua里有类似于C#里的internal hash table用于重用使用过的string和访问结果(C#里主要是使用过的string重用。Lua还能将访问过的string的table结果缓存返回)
但Auxiliary table有个缺点就是使用不频繁的string和result会一直被缓存无法释放。weak table正是用于解决这一问题的方案之一。(因为weak table的weak reference一旦不再被使用就会被下一次GC释放)
Object Attributes Implemetation
Solution: use external table to associate objects with attributes
Drawback: external table reference prevent objects from being collected
Final solution: use weak keys for objects in external tableTables with Default Values
这里有两种各有优缺点的实现方案:
方案1:1
2
3
4
5
6
7local defaults = {}
setmetatable(defaults, {__mode = "k"})
local mt = {__index = function (t) return defaults[t] end}
function (t, d)
defaults[t] = d
setmetatable(t, mt)
end
方案2:
1 | local metas = {} |
前者针对每一个不同的Table都会分配一个defaults入口,table作为key,default value作为value。这样的缺点就是当table数量很大的时候会需要分配很多内存去存储不同table的default value。
后者针对不同的default value分配了更多的内存(比如mt,entry on metas, closure……),但优点是同样的default value只需要分配一次即可,所以后者更适用于table数量多但default value大都相同的情况。
- Ephemeron Tables(声明短暂的table Lua 5.2里提供)
Ephemeron Table:
“In Lua 5.2, a table with weak keys and strong values is an ephemeron table. In an ephemeron table, the accessibility of a key controls the accessibility of its corresponding value.(只当有strong
reference to key时value才是strong的)”
e.g. constant-function factory
Note:
“Only objects can be collected from a weak table. Values, such as numbers and booleans, are not collectible”(只有Objects在weak table里能被gc回收,number和booleans这种Value类型不能在weak table里被gc回收)
“strings are collectible, but string is not removed from weak table(unless its associated value is collected)”
Finalizers
“Finalizers allow the collection of externa objects that are not directly under control of the garbage collector”
“Finalizer is a function associated with an object that is called when that object is about to be collected.”(相当于C#里的Finalize,在GC object的时候会被调用。但只有一开始设置Metamethod的gc时才能mark该object为可finalization的,否则就算后面在复制gc也不会在调用该object的finalizer)
Lua里是通过Metamethod里的__gc实现。
1 | -- 测试环境要求至少Lua 5.2 |
The order of finalization called:
“When the collector finalizes several obejcts in the same cycle, it calls their finalizers in the reverse order that the objects were marked for finalization”(先声明__gc被mark为可finalization的object的finalizer后被调用)
1 | -- 测试环境要求至少Lua 5.2 |
对于被finalize的object,Finlization会使被finalize的object处于两个特殊的状态:
- transient resurrection(短暂的复苏)
- permanent resurrection(永久的复苏)
前者因为在调用__gc的metamethod时我们会得到finalize的object,这样一来使得该object alive again,然后我们可以通过该object用于访问里面的对象。
finalizer被调用时,该alive again的object被存储在了global table里,导致该object在finalize后依然存在。要想使用finalize也真正回收obejct,我们需要调用两次gc,第一次用于回收原始object,第二次用于回收alive again的object。1
-- 因为当前测试环境是Lua 5.1(基于LuaTo#插件学习的,JIT支持到5.1的版本)所以不支持Talbe的__gc Metamethod,这里暂时没有写测试程序。
Note:
“In lua 5.1 the only lua values that work with gc metamethod is userdata. “(Lua 5.1不支持table的gc metamethod,只支持userdata的__gc metamethod)
Lua里的OOP
OOP(Object Oriented Programming)
首先Lua里面编写更重要的是Think in Lua,所以这里我不是强调OOP的重要性,而是单纯因为OOP被更多的C#程序员所熟悉。
Class抽象
1 | -- File Name: Class.lua |
上面的代码注释已经很清楚了,就不一一解释了。
理解上面Lua实现OOP的关键在于通过table模拟Class的抽象以及数据封装,通过metatable模拟继承特性。
Class定义
定义一个类的方式如下:
1 | 类名 = Class("类名") |
Class继承
继承一个类的方式如下:
1 | 子类名 = Class("子类名", 父类名) |
Class对象实例化
Lua OOP对象实例化方式如下:
1 | local 变量名 = New(类名) |
Lua小知识
Lua里没有Class只有通过Table模拟的Class
参考前面的Lua OOP实现Lua里没有this的概念,self不等价于this,函数调用传的是谁谁就是self。Lua里.定义和:定义相对于self的用法来说相当于静态和成员定义。
Lua里通过.调用的话是不会默认传递自身作为self的,不主动传的话self为空
Lua里通过:调用的话默认第一个参数就是调用者,既self1
2
3
4
5
6
7
8
9
10
11
12
13tab = {}
function tab.dotFunc(param)
print("self = ", self)
print(param)
end
function tab:colonFunc(param)
print("self = ", self)
print(param)
end
tab.dotFunc(1)
tab:colonFunc(1)
Note:
:只是起了省略第一个参数self的作用,该self指向调用者本身,并没有其他特殊的地方。Lua中的函数是带有词法定界(lexical scoping)的第一类值(first-class values)(在Lua中函数和其他值(数值、字符串)一样,函数可以被存放在变量中,也可以存放在表中,可以作为函数的参数,还可以作为函数的返回值)
1
2
3
4
5
6
7
8