目录
5.既然面向对象那么必要,为什么lua在设计时不实现面向对象?
14.package.loaded,require和package.searchers
0.前情废话
本着刷题刷到底,出攻略出到完的想法,虽然博主本人也没找到工作(甚至实习都没有QWQ,所以能给的帮助是非常少的喵),但是作为一棵愣头青,也不怕什么教会徒弟饿死师傅的了,毕竟师傅我呢,已经饿死了捏。
这篇主要谈的是:Lua,C#和XLua之间的关系,因为前文也提到了,博主是一员C#人柱力,哦不,应该叫unity人柱力,但是鄙人不善面试和笔试,似在半路非常合理,对的,过几天把什么引擎,算法之类的常问问题整理完也发一下,博主是这样子的,只要费心费力整理笔记就行了,而面试时的博主答不出来的就多了。
1.lua的深拷贝和浅拷贝
除了表都是浅拷贝。实现深拷贝的手段是local表+元表+元方法
2.lua元表的常用元方法有哪些?
元表的元方法:
1.__index:若表查询的值不存在,则调用__index的值(即该值允许是表或函数) 查询非法值时调用
__index的函数是固定的,为__index=function(tab,key) end,tab是表,key是查询的键,返回值是键对应的值
2.__newindex:当表添加新键时,__newindex会调用,他的函数也是固定的为: 添加新键值对时调用
__newindex=function(tab,key,value) end tab是表,key,value是对应的键值
哪怕值不存在也会调用
此外:若内部不设置rawset(tab,key,newvalue);语句,则当设置新键时,该键将设置失败
当__newindex对应的是表时,将会把新的键值赋值对应表,原表不赋值
3.__add:当两个表进行相加时调用,相加的两个表只要其中一个拥有__add即可 符号触发时调用
__add的函数也是固定的:__add=function(this tab,other tab) end
类似add的还有sub(减),mul,dv,mod,unm(负),concat(..),eq(==),lt(<),le(<=)
4.__call:当一个表具备__call键时,这个表可以像函数一样使用,只要传入参数即可调用__call方法 tab(参数群)时调用
__call=function(tab,参数群) end tab(参数群)
5.__tostring:当我们希望表进行输出时,__tostring会被调用,例如打印 print(tab)时调用
__tostring=function(tab) end
3.lua是怎么实现面向对象功能的?
面向对象的主要模块是封装继承和多态,通过local表+元表可以实现一个基本的类,通过元参数可以实现继承,通过重新指定功能实现多态
4.请用lua手动实现类
class = {};
function class:new(x)
local t = x or {};
setmetatable(t,{__index=self});
return t;
end
其中:x是为了实现继承功能OR构造函数
5.既然面向对象那么必要,为什么lua在设计时不实现面向对象?
因为lua的设计目标是轻量,简洁,易嵌入,可拓展和易学习,因此:而面向对象作为一个相对复杂的逻辑功能,自然被排除在外了。
6.lua有哪些数据类型
lua作为一个弱类型语言,包含的类型主要有:
nil,boolean,number,string,table,function,userdata和thread
7.请介绍一下lua的表和#
表是lua中一种非常强大的数据结构,能够表示数组,字典,集合等等概念。
其键值可以是任何类型,不过键通常是字符串和数字。
#获取的是表的最大连续整数索引序列,不是表的长度,即:若表中仅含数字键:且连续,那么获取的结果是对的,如果包含非数字键或者非连续数字键,那么:很可能是错的:此外最大连续整数索引序列≠最大连续整数序列,如
person={1,1,[4]=2};获取的结果是2
person={1,[4]=2};person[2]=3;获取的结果将是4,总之:非数组不用#,遍历就用pairs
8.pairs和ipairs
pairs和ipairs都是lua遍历表的常用关键字,但是ipairs只能遍历纯数字的表,pairs可以遍历整个表。
9.Lua和C#,XLUA之间的交互
lua和C#的交互主要是靠XLUA这类中间桥梁实现的。
C#通过XLUA提供的API完成环境配置,之后从lua中获取到它的全局属性。
Lua则可以通过XLUA提供的API调用C#的类,委托和事件,此外通过C#源文件对应的wrap文件调用C#能有效提高调用效率。
交互过程和原理:
C#将数据压入虚拟栈后调用C的dll库,C的dll库唤醒对应的lua文件,lua文件根据栈数据将指向结果压入栈顶,C#从栈顶吸收数据执行内容。。
lua文件调用C#的wrap文件/反射,wrap文件/反射在lua解析器中完成注册,lua根据解析器调用C#指定模块代码。
而XLUA做的工作就是:完成C#->执行->lua->执行->C#获取的两个执行的过程和Lua->wrap->C#的wrap过程。
10.什么是虚拟栈
虚拟栈是协助Lua和C#等各类数组完成交互的桥梁,可以是lua的任意类型元素,其有两个栈顶,分别是n和-1,1->n和-n->-1都越来越接近于栈顶。
11.lua的闭包是什么
简单说就是lua的函数在被创建的瞬间能够捕获其当前代码块作用域的所有变量,包含全局变量和局部变量。闭包功能使得即使我们在使用require关键字时:能够以一种最简洁的方式实现很多功能。
例如这块代码就很好地反应了闭包:
local d = 1;
function outerFunction(outerVar)
-- 这是一个闭包,因为它捕获了outerVar和下面的局部变量innerVar
return function(innerVar)
print("outerVar:", outerVar)print("innerVar:", innerVar)print(d);
endend
-- 创建一个闭包
myClosure = outerFunction(10)
-- 调用闭包
myClosure(20) -- 输出: outerVar: 10, innerVar: 20 1
12.什么是热更新
热更新是一种应用程序在运行时无需重启就能够进行应用自动更新和修复的技术,能够使开发者在不中断服务的前提:将新的内容提送到应用程序中。
13.LUA是怎么实现热更新的
热更新的基本逻辑是:检测代码源是否发生更改,->用代码加载器加载新的lua代码->用新代码替换旧代码->用新代码重新进行一次初始化。
LUA实现热更新主要是依赖:package.loaded,require,package.searchers等package相干函数实现的。
其中:大概流程为:
lua使用自定义require某个模块->向服务器进行版本比对->若有更新下载新版本的lua文件->将旧lua文件从package.loaded中移除->require新lua->返回新lua
14.package.loaded,require和package.searchers
package.loaded:lua的加载机制,所有被require的模块都将加入该表,当进行require时,先检测该表中是否含有指定模块,再进行返回。
package.searchers:package.loaded进行检测模块存在性的表
require:require指定路径的模块文件后:能得到指定模块的所有返回值,通常是表。
当一个模块的表被require时,结果能调用的是:所有该表的非local键均可被调用,无论这个键的值是否local,这就是闭包的好处。但是:
local function a:b() end是个特例,他不合法
15.LUA,XLUA和C#交互怎么防止内存泄漏
①减少C#和lua的循环转换,防止错误回收或者回收失败
②注意C#和lua的类型转换,虽然XLUA提供了userdata等机制很强,但是:lua的表的交互会转换为类或结构体,其他会转化为对应类型,而C#转lua也要注意类型问题
③C#持有lua对象时尽量使用弱引用
④减少C#和lua持有彼此对象的时间,尽快还给对应语言
⑤谁的变量谁回收
16.Lua的self参数
若一个表为:function a:b() end,则a:b()调用时,a将作为第一个参数:self传到函数b中。
17.Lua的垃圾回收机制
lua的垃圾回收机制是“Mard and Sweep”,检测MS机制(其实也是GC),利用C的malloc和free完成回收,但是C#做了更多优化,而lua在处理大量数据或者复杂数据还是容易产生垃圾碎片,流程为:
1.标记活动对象,并则选出其中的弱引用对象
2.进行分代处理,同C#,刚创建是1代(C#是0-1-2),代数高的:检测频率低
3.回收没标记的和已经走出代码块的弱引用对象。