lua相关的知识点(面试必问)

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 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) 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语言是脚本型语言,不需要进行编译即可运行,所以可以作为游戏热更的一种中间语言

猜你喜欢

转载自blog.csdn.net/lml_w/article/details/127863503