Lua 的元表
元表:可以将一个表设置为另外一个表的元表,通过元方法对元表进行操作。
元方法
__index:
调用table的一个不存在的索引时,会使用到元表的__index元方法,和前几个元方法不同,__index可以是一个函数也可是一个table。
作为函数:将表和索引作为参数传入__index元方法,return一个返回值
主要是作为一个查询操作
local t={
}
--第一个参数的表自己,第二个参数是调用的索引
t.__index =function(t,key)
return "is the table"..key
end
mt={
1,2,3}
print(mt.key)--为nil,没有设置其元表
setmetatable(mt,t)
--将t设置为mt的元表
print(mt.key)
__newindex:
当为table中一个不存在的索引赋值时,会去调用元表中的__newindex元方法(如果不重写该方法,原有的_newindex会在原来的表中添加新的索引)
主要表现为赋值操作,当元表中没有这个key值时,对他进行赋值。
Lua的面向对象
一个类就是创建对象的模具,对象又是某个特定类的实例;在Lua中table可以有属性(成员变量),也可以有成员方法(通过table+function实现);因此可以通过table来描述对象的属性
lua实现单例模式
主要使用其__index和 __newindex 元方法
讲到面向对象,必须需要了解冒号和点号的使用。
lua的冒号: 和点号.区别
Lua中实现表的只读
只读表的使用场景 :游戏中大量使用了导表数据,具体为策划通过excel表格填好游戏中需要使用的数据,然后通过工具转化为游戏中的数据内容。在MMO中使用的很多
设计思路:将lua中元方法__newindex禁用,并且不能修改表中原有的数据,lua并没有提供更改的接口,所以要将其转化为新增问题。
按照这个思路一步步来,如下方的代码
-- 不能更改原来的值,不能添加新键值对
local readOnly = function(t)
local tn = {
} -- 创建一个新的空表
local tm = {
__index = t, -- 读取的时候,使其读取传进来的表
__newindex = function(t, key, value) -- 新增就报错,因为tn是空表,所以不会有更改已有元素的操作,所有赋值操作都是新增
error("this is a readonly table")
end
}
setmetatable(tn, tm)
return tn -- 返回新创建的空表
end
--在这里,只实现了表的一层,假如表内嵌套一个表,那么里面的这个表还是会改变,所以使用递归表里的所有数据
-- 递归地改变表里的所有表为只读
local readOnly = function(t)
for k, v in pairs(t) do
if type(v) == "table" then
t[k] = readOnly(v)
end
end
local tn = {
}
local tm = {
__index = t,
__newindex = function(t, key, value)
error("this is a readonly table")
end
}
setmetatable(tn, tm)
return tn
end
Lua的深拷贝和浅拷贝
在lua中类型:nil、boolean、number、string、function等可以直接通过=进行拷贝,类似于C#的值类型,=左边的数进行改变,不影响右边的。这一类,称之为赋值拷贝。如下代码
local nA = 10
local nB = nA
print(nB)
nB=8
print("nA:"..nA)
print("nB:"..nB)
--输出
-- 10
-- nA:10
-- nB:8
浅拷贝
对于表来说的,相当于起别名,一个表table 叫tA,也叫tB,改变tA的内容,tB也改变,反之亦然
local tA = {
[1]=1,[2]=2,[3]=3,[5]=5}
local tB = tA
print("tA[2]:"..tA[2]) --tA[2]:2
print("tB[2]:"..tB[2]) --tB[2]:2
tA[2] = 19
print("------================================")
print("tA[2]:"..tA[2]) --tA[2]:19
print("tB[2]:"..tB[2]) --tB[2]:19
深拷贝
已经复制过的table,key为复制源table,value为复制后的table
为了防止table中的某个属性为自身时出现死循环
避免本该是同一个table的属性,在复制时变成2个不同的table(及内容同,但是地址关系和原来的不一样了)
function DeepCopy(object)
local lookup_table = {
}
local function _copy(object)
if type(object) ~= 'table' then -- 非table类型都直接返回
return object
elseif lookup_table[object] then
return lookup_table[object]
end
local new_table = {
}
lookup_table[object] = new_table
for k,v in pairs(object) do
new_table[_copy(k)] = _copy(v)
end
-- 这里直接拿mt来用是因为一般对table操作不会很粗暴的修改mt的相关内容
return setmetatable(new_table, getmetatable(object))
end
return _copy(object)
end
Lua的遍历 循环
主要有lua pairs 和ipairs ,还有next等。主要看下面的事例
pairs 和 ipairs 的区别在于,ipairs遍历Table的时候,遇到元素为nil的时候直接返回,而pairs会将表内的数据全部遍历,遇到nil不会返回。
第一种循环方式。类似于数组的下标读取表的元素,没有时为nil
local tTemp = {
[1]=1,[2]=2,[3]=3,[5]=5}
for i=1,6 do
-- print(i)
print(i,tTemp [i])
end
--输出
--1 1
--2 2
--3 3
--4 nil
--5 5
--6 nil
第二种,pairs
local tTemp = {
[1]=1,[2]=2,[3]=3,[5]=5}
for i,vaule in ipairs(tTemp) do
print(i,vaule)
end
--输出
--1 1
--2 2
--3 3
--5 5
第三种, ipairs
local tTemp = {
[1]=1,[2]=2,[3]=3,[5]=5}
for i,vaule in ipairs(tTemp) do
print(i,vaule)
end
--输出
--1 1
--2 2
--3 3
第四种,next
local tTemp = {
[1]=1,[2]=2,[3]=3,[5]=5}
for i,vaule in next ,tTemp do
print(i,vaule)
end
--输出
--1 1
--2 2
--3 3
--5 5
其他
lua语言是脚本型语言,不需要进行编译即可运行,所以可以作为游戏热更的一种中间语言