lua相关的知识点(面试必问)
迪丽瓦拉
2024-05-31 14:11:41
0

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) doif type(v) == "table" thent[k] = readOnly(v)endendlocal 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]:2tA[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 objectelseif lookup_table[object] thenreturn lookup_table[object]end local new_table = {}lookup_table[object] = new_tablefor k,v in pairs(object) donew_table[_copy(k)] = _copy(v) end -- 这里直接拿mt来用是因为一般对table操作不会很粗暴的修改mt的相关内容return setmetatable(new_table, getmetatable(object))end return _copy(object)                    
end

Lua的遍历 循环

主要有lua pairsipairs ,还有next等。主要看下面的事例
pairsipairs 的区别在于,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) doprint(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) doprint(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 doprint(i,vaule)
end
--输出
--1	  1
--2   2
--3	  3
--5   5

其他

lua语言是脚本型语言,不需要进行编译即可运行,所以可以作为游戏热更的一种中间语言

相关内容