EmmyLua 学习使用
<h3 id="目录">目录</h3>
- lua元表
- class的探索
要想对lua有更加深入的了解,不深入的了解lua的元表是不行的,在lua中元表是你构建一个复杂的数据结构的基础,所以需要对元表有非常深入的了解。
元表允许改变table的行为,每个行为关联对应的原方法。
在这里有两个关于元表非常重要的方法:
- setmetatable(table,metatable)
- getmetatable(table)
元表(metatable)中存在 __metatable 键值,则会设置和返回失败 __metatable键值是用于安全考虑,可以防止获取和修改元表中的内容。
元方法是关联两个元表的桥梁,是非常重要的,下面介绍几个重要的元方法。
元方法
元方法一共分为两种:
- 系统使用的元方法
- 自定义的元方法
系统使用的元方法
算术元方法以及逻辑元方法:
__cancat用于字符串
模式 | 描述 |
---|---|
__add | 加 |
__sub | 减 |
__mul | 乘 |
__div | 除 |
__mod | 取余 |
__unm | 负号 |
__pow | 取幂 |
__concat | … |
__eq | == |
__lt | < |
__le | <= |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
local table1 = {1,2,3}
local table2 = {4,5,6}
local fn = function (t1,t2) -----table会被传入作为参数
local newtable = {}
for i=1,3 do
newtable[i] = t1[i] + t2[i]
end
return newtable
end
setmetatable(table2,{__add = fn})
local newtable = table1+table2
for k,v in pairs(newtable) do
print("newtable --",k,v)
end
--打印结果:
--newtable -- 1 5
--newtable -- 2 7
--newtable -- 3 9
两表相加,必须至少其中一个表设置了带__add键的元表,否侧会报错(其他运算符同理),进程会执行__add对应的函数。如果两个表都设置了有__add键的元表,进程会去执行“+”左侧的表中的元表的__add对应的函数。
table访问的元方法:
__index 和 __newindex
__index的作用,访问当前table的时候,发现没有这个键值,那个table就会去寻找metatable中__index元,如果存在__index,就去__index包含表格,就去表中寻找键值。当__index为函数时,则调用方法。方法会默认传入两个参数,一个是self,另一个是key值
1
2
3
4
5
6
7
8
mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "metatablevalue" } })
print(mytable.key1,mytable.key2) --value1 metatablevalue
local function fn(table, key)
print(“table and key”,table,key)
end
mytablefun = setmetatabke({key1 = “value1”}, { __index = fn )
总结: Lua 查找一个表元素时的规则,其实就是如下 3 个步骤:
- 在表中查找,如果找到,返回该元素,找不到则继续
- 判断该表是否有元表,如果没有元表,返回 nil,有元表则继续。
- 判断元表有没有 __index 方法,如果 __index 方法为 nil,则返回 nil;如果 __index 方法是一个表,则重复 1、2、3;如果 __index 方法是一个函数,则返回该函数的返回值。
查询:访问表中不存的字段 :rawget(t, i)
__newindex,方法是用来对表进行更新,__index则用来对表访问 。
当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果存在则调用这个函数而不进行赋值操作。
当table不存在键值的时候,__newindex为table,则可以_newindex包含的table来访问这个key值,如果__newindex为函数,直接直接调用函数。 更新:向表中不存在索引赋值 :rawset(t, k, v)
rawget与rawset 直接访问和设置table而不会去访问元方法__index 和 __newindex,也就不会去更新表了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })
print(mytable.key1)
mytable.newkey = “新值2”
print(mytable.newkey,mymetatable.newkey)
mytable.key1 = “新值1”
print(mytable.key1,mymetatable.key1)
– value1
– nil 新值2
– 新值1 nil
function fn (table,key,value)
print(table,“n”,key,“n”,value)
end
local tableB = {k1 = “Hi”}
setmetatable(tableB,{__newindex = fn}) —会将table、key、value传给fn作为参数
tableB.k2 = “Good”
–打印结果:
–table: 000000000256a650
– k2
– Good
__call 元方法让表成为函数,可以带参数,即此元方法在 Lua 调用一个值时调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function table_maxn(t)
local mn = 0
for k, v in pairs(t) do
if mn < k then
mn = k
end
end
return mn
end
– 定义元方法__call
mytable = setmetatable({10}, {
__call = function(mytable, newtable)
sum = 0
for i = 1, table_maxn(mytable) do
sum = sum + mytable[i]
end
for i = 1, table_maxn(newtable) do
sum = sum + newtable[i]
end
return sum
end
})
newtable = {10,20,30}
print(mytable(newtable))
__tostring,可以自定义table的输出行为
1
2
3
4
5
6
7
8
9
10
local table = {q,b,c}
local function fn(t)
return "Hello here"
end
setmetatable(table,{__tostring = fn})
print(table)
–打印结果:
–Hello here
class的探索
在游戏开发的过程中,一般使用的都是面向对象的开发方式,但在脚本语言中是不存在类、方法以及属性这些概念的,所以要使用这个特性的第一步就是实现一个叫class的全局函数,通过调用这个函数来实现类的生成。但是cocos的这个class还是存在一些问题,接下来认真的解析和测试一下class。
https://blog.csdn.net/mywcyfl/article/details/37706247
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
function class(classname, super)
local superType = type(super)
local cls
<span class="c1">--如果父类既不是函数也不是table则说明父类为空</span>
<span class="k">if</span> <span class="n">superType</span> <span class="o">~=</span> <span class="s2">"function"</span> <span class="ow">and</span> <span class="n">superType</span> <span class="o">~=</span> <span class="s2">"table"</span> <span class="k">then</span>
<span class="n">superType</span> <span class="o">=</span> <span class="kc">nil</span>
<span class="n">super</span> <span class="o">=</span> <span class="kc">nil</span>
<span class="k">end</span>
<span class="c1">--如果父类的类型是函数或者是C对象</span>
<span class="k">if</span> <span class="n">superType</span> <span class="o">==</span> <span class="s2">"function"</span> <span class="ow">or</span> <span class="p">(</span><span class="n">super</span> <span class="ow">and</span> <span class="n">super</span><span class="p">.</span><span class="n">__ctype</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="k">then</span>
<span class="c1">-- inherited from native C++ Object</span>
<span class="n">cls</span> <span class="o">=</span> <span class="p">{}</span>
<span class="c1">--如果父类是表则复制成员并且设置这个类的继承信息</span>
<span class="c1">--如果是函数类型则设置构造方法并且设置ctor函数</span>
<span class="k">if</span> <span class="n">superType</span> <span class="o">==</span> <span class="s2">"table"</span> <span class="k">then</span>
<span class="c1">-- copy fields from super</span>
<span class="k">for</span> <span class="n">k</span><span class="p">,</span><span class="n">v</span> <span class="k">in</span> <span class="nb">pairs</span><span class="p">(</span><span class="n">super</span><span class="p">)</span> <span class="k">do</span> <span class="n">cls</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span> <span class="k">end</span>
<span class="n">cls</span><span class="p">.</span><span class="n">__create</span> <span class="o">=</span> <span class="n">super</span><span class="p">.</span><span class="n">__create</span>
<span class="n">cls</span><span class="p">.</span><span class="n">super</span> <span class="o">=</span> <span class="n">super</span>
<span class="k">else</span>
<span class="n">cls</span><span class="p">.</span><span class="n">__create</span> <span class="o">=</span> <span class="n">super</span>
<span class="n">cls</span><span class="p">.</span><span class="n">ctor</span> <span class="o">=</span> <span class="k">function</span><span class="p">()</span> <span class="k">end</span>
<span class="k">end</span>
<span class="c1">--设置类型的名称</span>
<span class="n">cls</span><span class="p">.</span><span class="n">__cname</span> <span class="o">=</span> <span class="n">classname</span>
<span class="n">cls</span><span class="p">.</span><span class="n">__ctype</span> <span class="o">=</span> <span class="mi">1</span>
<span class="c1">--定义该类型的创建实例的函数为基类的构造函数后复制到子类实例</span>
<span class="c1">--并且调用子数的ctor方法</span>
<span class="k">function</span> <span class="nc">cls</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">instance</span> <span class="o">=</span> <span class="n">cls</span><span class="p">.</span><span class="n">__create</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="c1">-- copy fields from class to native object</span>
<span class="k">for</span> <span class="n">k</span><span class="p">,</span><span class="n">v</span> <span class="k">in</span> <span class="nb">pairs</span><span class="p">(</span><span class="n">cls</span><span class="p">)</span> <span class="k">do</span> <span class="n">instance</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span> <span class="k">end</span>
<span class="n">instance</span><span class="p">.</span><span class="n">class</span> <span class="o">=</span> <span class="n">cls</span>
<span class="n">instance</span><span class="p">:</span><span class="n">ctor</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">return</span> <span class="n">instance</span>
<span class="k">end</span>
<span class="k">else</span>
<span class="c1">--如果是继承自普通的lua表,则设置一下原型,并且构造实例后也会调用ctor方法</span>
<span class="c1">-- inherited from Lua Object</span>
<span class="k">if</span> <span class="n">super</span> <span class="k">then</span>
<span class="n">cls</span> <span class="o">=</span> <span class="p">{}</span>
<span class="nb">setmetatable</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="p">{</span><span class="n">__index</span> <span class="o">=</span> <span class="n">super</span><span class="p">})</span>
<span class="n">cls</span><span class="p">.</span><span class="n">super</span> <span class="o">=</span> <span class="n">super</span>
<span class="k">else</span>
<span class="n">cls</span> <span class="o">=</span> <span class="p">{</span><span class="n">ctor</span> <span class="o">=</span> <span class="k">function</span><span class="p">()</span> <span class="k">end</span><span class="p">}</span>
<span class="k">end</span>
<span class="n">cls</span><span class="p">.</span><span class="n">__cname</span> <span class="o">=</span> <span class="n">classname</span>
<span class="n">cls</span><span class="p">.</span><span class="n">__ctype</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1">-- lua</span>
<span class="n">cls</span><span class="p">.</span><span class="n">__index</span> <span class="o">=</span> <span class="n">cls</span>
<span class="k">function</span> <span class="nc">cls</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">instance</span> <span class="o">=</span> <span class="nb">setmetatable</span><span class="p">({},</span> <span class="n">cls</span><span class="p">)</span>
<span class="n">instance</span><span class="p">.</span><span class="n">class</span> <span class="o">=</span> <span class="n">cls</span>
<span class="n">instance</span><span class="p">:</span><span class="n">ctor</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">return</span> <span class="n">instance</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">return</span> <span class="n">cls</span>
end
<hr style="visibility: hidden;">