当前位置:网站首页>【Lua】常见知识点汇总(包含常见面试考点)
【Lua】常见知识点汇总(包含常见面试考点)
2022-07-02 06:36:00 【趁着头发多我想做游戏】
版权声明:本文为CSDN博主「趁着头发多我想做游戏」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_37658157/article/details/123604068
目录
1. 如何在Lua中实现一个私有变量或者函数
思路:Lua中并没有private或者public这样的关键字,如果希望某些字段或者函数变为私有,只需要不暴露这些字段或者函数出去即可。
代码如下:
-- Test.lua
local v = {
}
v.x = 100
v.y = 200
function v:new()
local ins = {
}; --实例化一个对象ins
setmetatable(ins, self); --访问对象ins时会去找v里面的字段和方法
self.__index = {
--对外提供f函数以及字段x、y,注意g函数没有暴露出去
f = self.f,
x = self.x,
y = self.y
}
return ins
end
function v:f()
return v:g()
end
function v:g()
return self.x + self.y
end
return v
-- Main.lua
local t = require("Test")
local ins = t:new()
local a = ins:f()
print("访问公共函数",a)
local c = ins:g()
print("访问私有函数",c)
运行结果:
访问公共函数 300
attempt to call a nil value (method 'g')
由于函数g并没有被导出(即函数g是一个私有函数),因此访问就会出错。私有字段也是同理,不再赘述。注意,不一定要用元表的方式,也可以加载一个类时返回一个临时表,如:
return {
f = f, x = x, y = y}
2. loadfile、loadstring、dofile、require的区别
- loadfile:传入路径,编译代码成中间码并且返回编译后的 chunk 作为一个函数,而不执行代码;
- loadstring(lua5.4中已废弃,改为load):跟loadfile类似,但是传入的是string,可以直接执行lua代码,注意返回的也是一个函数,需要手动调用;
- dofile:传入lua文件的路径,执行loadfile后调用一次,代码如下:
function dofile (filename)
local f = assert(loadfile(filename)) --如果 loadfile 失败 assert 会抛出错误。
return f() -- 根据loadfile的返回函数运行一遍
end
- require:跟dofile类型,不同的是require还具有搜索目录加载文件的功能,以及会判断文件是否已经加载过,若加载过则不再加载,代码如下:
function require(name)
if not package.loaded[name] then --模块是否已加载?
local loader = findloader(name)
if loader == nil then
error("unable to load module"..name)
end
package.loaded[name] = true --将模块标记为已加载
local res = loader(name) --初始化模块
if res ~=nil then
package.loaded[name] = res
end
end
return package.loaded[name]
end
如果希望加载过的文件再次加载,则执行
package.loaded[name] = nil
然后再次require即可
3. 如何在Lua中同步调用异步函数
思路:使用Lua的协程,异步调用时先挂起,执行结束后恢复即可,代码如下(参考链接)
--传入一个async方法
local function async_to_sync(async_func, callback_pos)
--返回一个sync方法
return function(...)
--取当前正在运行的协程,若不存在则报错(说明只能在协程中使用!)
local _co = coroutine.running() or error ('this function must be run in coroutine')
--定义 结果
local rets
--定义 等待标记
local waiting = false
--定义 完成时的回调
local function cb_func(...)
if waiting then
--等待后回调的情况
--从挂起的位置恢复协程,并传递结果
assert(coroutine.resume(_co, ...))
else
--未等待就直接回调的情况,直接设置结果
rets = {
...}
end
end
--参数列表 把 “回调” 加入参数列表(默认加入最后)
local params = {
...}
table.insert(params, callback_pos or (#params + 1), cb_func)
--调用异步方法,把 “通过同步方法传入的参数” 和 “回调” 全部传给异步方法。
async_func(unpack(params))
--如果没有立即返回,则标记为等待并挂起
if rets == nil then
waiting = true
--挂起! "coroutine.yield()" 的返回值为 coroutine.resume 传入的第二个参数
rets = {
coroutine.yield()}
end
--将结果同步返回
return unpack(rets)
end
end
4. 什么情况下调用函数可以省略 “()”
在Lua中,当函数的入参只有一个表或者字符串时,可以省略“()”进行函数调用,以下代码都是合法的:
print "hello world"
print {
}
注意,在这种情况下如果函数的参数列表是不定参数,则 “…” 等价于一个传入的参数本身,以下代码都是合法的:
function test_func(...)
print("test:",...)
test_func2(...,10)
end
function test_func2(tb,num)
print("test1:",tb,num)
end
test_func {
}
输出:
test: table: 000001C390C91E40
test1: table: 000001C390C91E40 10
5. 如何实现Lua的深拷贝
思路:对于非table类型的数据,无需拷贝直接返回自身,否则递归遍历拷贝table中的所有元素,注意需要用元表来“拷贝”目标的元表的数据,代码如下:
-- Lua table deep copy
function clone(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 key, value in pairs(object) do
new_table[_copy(key)] = _copy(value) --递归遍历table的元素
end
return setmetatable(new_table, getmetatable(object)) --拷贝目标的元表的数据
end
return _copy(object)
end
6. Lua与C之间的相互调用
Lua作为一种轻量型的“胶水”语言,很多情况下需要和其他高级语言进行相互调用以满足日常需求。
Lua完全不同于其他高级语言,要实现相互调用,需要借助一个“虚拟栈”的东西,再按照约定好的操作流程(相当于协议),就可以进行调用。
参考资料:
1. Lua与C语言的互相调用
2. tolua之wrap文件的原理与使用
7.调用父类同名函数时使用self.super:Func()存在的问题
在其他高级语言中调用父类同名函数常常使用 this.super:Func() 的形式,而在Lua中这样的使用会存在问题,假设A为父类,B为子类, 都有Ctor()函数:
function A:Ctor(...)
self.super:Ctor(...)
end
function B:Ctor(...) --继承了A
self.super:Ctor(...)
end
function Test()
local b = B.New()
b:Ctor() --调用后,B的Ctor中的self和A的Ctor中的self都指向同一个对象(即b)
end
由于Lua中的冒号访问是默认把当前调用者当成第一个参数传入到函数当中,AB两处的self实际上指向同一个对象,即上述代码实际上运行如下:
function A:Ctor(...)
self.super:Ctor(...) --2. self为b,此时调用A.Ctor(b,...),引起死循环
end
function B:Ctor(...) --继承了A
self.super:Ctor(...) --1. self为b,self.super指向A,此时调用 A.Ctor(b,...)
end
正确的写法是明确指定函数的调用者以及传入哪个self:
function A:Ctor(...)
A.super.Ctor(self,...) --2. A.super只能是A的父类(假设有),不存在上述死循环的可能
end
function B:Ctor(...) --继承了A
B.super.Ctor(self,...) --1. B.super只能是A,此时调用A.Ctor(b,...)
end
8.如何让一个表变为只读(ReadOnly)
利用元方法__newindex可以干预写入行为的特性即可:
function table.SetReadOnly(tb)
setmetatable(tb, {
__newindex = function(t, k, v)
error("attempt to modify a read-only table!")
end
})
end
9.如何用Lua实现一个类(Class)
思路:首先类最重要的特性是继承,也就是访问一个子类的函数或字段时,若子类没有该函数或字段,则向上递归尝试寻找父类的同名函数与字段(即子类隐式包含父类的函数与字段);Lua没有继承语法糖,但是可以通过元表和元方法模拟类的行为。
function Class(classname, super)
local superType = type(super)
local cls
if superType ~= "function" and superType ~= "table" then
superType = nil
super = nil
end
if super then
cls = {
}
setmetatable(cls, {
__index = super}) --子类继承父类
cls.super = super
else
cls = {
Ctor = function() end} --提供一个默认的构造函数
end
cls.__cname = classname
cls.__index = cls
function cls.New(...)
local instance = setmetatable({
}, cls)
instance.class = cls
instance:Ctor(...)
return instance
end
return cls
end
边栏推荐
- 2837xd code generation module learning (4) -- idle_ task、Simulink Coder
- XA Transaction SQL Statements
- 【虚幻】武器插槽:拾取武器
- 【虚幻】过场动画笔记
- 【虚幻】按键开门蓝图笔记
- [unreal] key to open the door blueprint notes
- What is the relationship between realizing page watermarking and mutationobserver?
- 虚幻材质编辑器基础——如何连接一个最基本的材质
- Minimum number of C language
- 滲透測試的介紹和防範
猜你喜欢
Blender模型导入ue、碰撞设置
Personal experience & blog status
【虚幻】按键开门蓝图笔记
Large neural networks may be beginning to realize: the chief scientist of openai leads to controversy, and everyone quarrels
Beautiful and intelligent, Haval H6 supreme+ makes Yuanxiao travel safer
Eslint reports an error
ESLint 报错
【虚幻4】从U3D到UE4的转型之路
[Yu Yue education] University Physics (Electromagnetics) reference materials of Taizhou College of science and technology, Nanjing University of Technology
Error reporting on the first day of work (incomplete awvs unloading)
随机推荐
2837xd代码生成模块学习(4)——idle_task、Simulink Coder
Data insertion in C language
The latest progress and development trend of 2022 intelligent voice technology
Project practice, redis cluster technology learning (6)
Vscode set JSON file to format automatically after saving
虛幻AI藍圖基礎筆記(萬字整理)
Metaclass type and using metaclass to implement model class ORM
【虚幻】武器插槽:拾取武器
2837xd 代码生成——StateFlow(2)
ESLint 报错
Project practice, redis cluster technology learning (10)
Remember the use of add method once
Eslint reports an error
Beautiful and intelligent, Haval H6 supreme+ makes Yuanxiao travel safer
Configuration programmée du générateur de plantes du moteur illusoire UE - - Comment générer rapidement une grande forêt
Introduction to go language
2837xd code generation - stateflow (1)
Commutateur Multi - lentilles Blender
【虚幻】按键开门蓝图笔记
2837xd 代碼生成——補充(1)