版权声明:本文为CSDN博主「趁着头发多我想做游戏」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_37658157/article/details/123604068

目录

  • 1. 如何在Lua中实现一个私有变量或者函数
  • 2. loadfile、loadstring、dofile、require的区别
  • 3. 如何在Lua中同步调用异步函数
  • 4. 什么情况下调用函数可以省略 “()”
  • 5. 如何实现Lua的深拷贝
  • 6. Lua与C之间的相互调用
  • 7.如何让一个表变为只读(ReadOnly)
  • 8.如何用Lua实现一个类(Class)

1. 如何在Lua中实现一个私有变量或者函数

思路:Lua中并没有private或者public这样的关键字,如果希望某些字段或者函数变为私有,只需要不暴露这些字段或者函数出去即可。

代码如下:

-- Test.lualocal v = {}
v.x = 100
v.y = 200function v:new()local ins = {};             --实例化一个对象inssetmetatable(ins, self);    --访问对象ins时会去找v里面的字段和方法self.__index = {            --对外提供f函数以及字段x、y,注意g函数没有暴露出去f = self.f,x = self.x,y = self.y}return ins
endfunction v:f()return v:g()
endfunction v:g()return self.x + self.y
endreturn 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的区别

  1. loadfile:传入路径,编译代码成中间码并且返回编译后的 chunk 作为一个函数,而不执行代码;
  2. loadstring(lua5.4中已废弃,改为load):跟loadfile类似,但是传入的是string,可以直接执行lua代码,注意返回的也是一个函数,需要手动调用;
  3. dofile:传入lua文件的路径,执行loadfile后调用一次,代码如下:
function dofile (filename)local f = assert(loadfile(filename)) --如果 loadfile 失败 assert 会抛出错误。return f() -- 根据loadfile的返回函数运行一遍
end
  1. require:跟dofile类型,不同的是require还具有搜索目录加载文件的功能,以及会判断文件是否已经加载过,若加载过则不再加载,代码如下:
function require(name)if not package.loaded[name] then --模块是否已加载?local loader = findloader(name)if loader == nil thenerror("unable to load module"..name)endpackage.loaded[name] = true --将模块标记为已加载local res = loader(name)    --初始化模块if res ~=nil thenpackage.loaded[name] = resend 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 = {...}endend--参数列表 把 “回调” 加入参数列表(默认加入最后)local params = {...}table.insert(params, callback_pos or (#params + 1), cb_func)--调用异步方法,把 “通过同步方法传入的参数” 和 “回调” 全部传给异步方法。async_func(unpack(params))--如果没有立即返回,则标记为等待并挂起if rets == nil thenwaiting = 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 objectelseif lookup_table[object] then   --找过的就不用再找了return lookup_table[object]endlocal new_table = {}lookup_table[object] = new_tablefor key, value in pairs(object) donew_table[_copy(key)] = _copy(value)  --递归遍历table的元素endreturn setmetatable(new_table, getmetatable(object))   --拷贝目标的元表的数据endreturn _copy(object)
end

6. Lua与C之间的相互调用

Lua作为一种轻量型的“胶水”语言,很多情况下需要和其他高级语言进行相互调用以满足日常需求。
Lua完全不同于其他高级语言,要实现相互调用,需要借助一个“虚拟栈”的东西,再按照约定好的操作流程(相当于协议),就可以进行调用。
参考资料:
1. Lua与C语言的互相调用
2. tolua之wrap文件的原理与使用

7.如何让一个表变为只读(ReadOnly)

利用元方法__newindex可以干预写入行为的特性即可:

function table.SetReadOnly(tb)  setmetatable(tb, {__newindex = function(t, k, v)error("attempt to modify a read-only table!")end})
end

8.如何用Lua实现一个类(Class)

思路:首先类最重要的特性是继承,也就是访问一个子类的函数或字段时,若子类没有该函数或字段,则向上递归尝试寻找父类的同名函数与字段(即子类隐式包含父类的函数与字段);Lua没有继承语法糖,但是可以通过元表和元方法模拟类的行为。

---创建类
---@param className string 类名
---@param superClass table|function|nil Class 父类
function Class(className, superClass)local clazz = {}clazz._className = classNamelocal superType = type(superClass)if superType == "function" or superType == "table" thensetmetatable(clazz,{__index = superClass})        --实现继承的关键代码clazz._super = superClasselseclazz.Ctor = function ()  end         --提供一个默认的构造函数endfunction clazz.New(...)local instance = {}setmetatable(instance,{__index = clazz})        --实现:类的实例访问类的字段或函数instance._class = clazzinstance:Ctor(...)return instanceendreturn clazz
end

避坑指南:派生类需要调用父类的同名函数时,不能使用 self._super:XXX() 的方式,而要用 className._super.XXX(self) 的方式,比如:

local Object = Class("Object")
function Object:Ctor()self.tb = {}
end
local ClsA = Class("ObjectA",Object)
function ClsA:Ctor()-- self._super:Ctor() -- 错误ClsA._super.Ctor(self) -- 正确
end

原因在于,派生类的 _super 指向的是一个父类表,不同的对象调用 self._super:Ctor() 之后, self.tb 这张表实际上是存储在父类表中,而不是存储于实例对象中,因此不同的派生对象通过 self.tb 访问时,实际上都是访问父类中的 tb。而 ClsA._super.Ctor(self) 因为是用点访问而不是冒号访问,入参传入的是自身self,因而 self.tb = {} 就等同于 ClsA.tb = {} 自然也就解决了这个问题。

【Lua】常见知识点汇总(包含常见面试考点)相关推荐

  1. Java常见知识点汇总

    Java常见知识点汇总 基础概念与常识 1.Java 语言有哪些特点? 2.JVM vs JDK vs JRE 3.什么是字节码?采用字节码的好处是什么? 4.为什么不全部使用 AOT 呢? 5.为什 ...

  2. php cakephp like,cakephp常见知识点汇总

    本文实例总结了cakephp常见知识点.分享给大家供大家参考,具体如下: 1. 调用其他控制器的模板,重定向 方法一: 在此调用/views/tasks/tasks下的hello.ctp模板 $thi ...

  3. 工业交换机常用术语及常见知识点汇总

    工业交换机作为现在最流行也最高效率的数据通信设备,它本身就是一款高科技产品.是产品就有很多的参数和指标,很多采购的朋友,可能只是按照公司的要求来进行筛选对应的产品,对工业交换机的了解不是很深入,甚至对 ...

  4. Java 集合Collection常见知识点汇总~

    看了一些所谓大公司的JAVA面试问题,发现对于JAVA集合类的使用都比较看重似的,而自己在这方面还真的是所真甚少,抽空也学习学习吧. java.util包中包含了一系列重要的集合类,而对于集合类,主要 ...

  5. java虚成员函数_Java常见知识点汇总(④)——虚函数、抽象函数、抽象类、接口...

    一. Java虚函数 虚函数的存在是为了多态. 它虚就虚在所谓"推迟联编"或者"动态联编"上,一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的. ...

  6. Global Mapper常见技巧汇总(常见格式转换,影像拼接,几何纠正....)

    Global Mapper作为一个辅助工具,在工作中的使用频率是很高的,至少在小助手工作中每天都是必不可少的.今天小助手就来汇总下工作中用的比较多而且自我感觉比较实用的几个工具吧. " 卷帘 ...

  7. 计算机二级大题知识点汇总,计算机二级Excel考点与做题技巧汇总。

    #计算机二级# NO.1.开始选项卡 一.单击右键可以设置的内容 1.新建表.删除表.移动复制工作表.选择性粘贴.断开链接 2.重命名工作表.隐藏工作表.设置工作表标签颜色 3.行和列的插入.删除.移 ...

  8. java 常见异常汇总_Java常见异常总结

    1. java.lang.NullPointerException(空指针异常) 调用了未经初始化的对象或者是不存在的对象 经常出现在创建图片,调用数组这些操作中,比如图片未经初始化,或者图片创建时的 ...

  9. 中考计算机必背知识点,2019中考英语必背知识点汇总 常见考点总结

    2019中考英语必背知识点汇总 常见考点总结2018-09-15 17:08:57文/王蕊 英语知识点是必须掌握的, 下面初三网小编就大家整理一下2019中考英语必背知识点汇总,仅供参考. 复合不定代 ...

最新文章

  1. 小鸭脖大生意——绝味鸭脖背后的故事
  2. Java中的主类概念以及public static void main方法的分析
  3. 用数据库实现了一个分布式锁,虽简陋,但能用!
  4. 开源 免费 java CMS - FreeCMS1.3-数据对象-mail
  5. 一、Web服务器——Tomcat Servlet学习笔记
  6. java dateutils_Java DateUtils java时间工具类 kaki的博客
  7. CentOS忘记普通用户密码解决办法
  8. Spring.NET实用技巧1——基于Prevalence下的NHibernate二级缓存使用技巧
  9. [转]“新欢乐时光”病毒源代码分析
  10. sql获取字符串长度函数
  11. github android官方客户端,github安卓手机版APK下载-github Android客户端下载v2.0 官方版-腾牛安卓网...
  12. 百度蜘蛛的工作原理,什么内容才容易被百度蜘蛛抓取?
  13. Android SDK 字段及功能的分析详解
  14. 配置 择时 sel stock
  15. 程序员常见10大口头禅
  16. 电影暗杀了一只巨可爱的猫[转帖]
  17. 负载均衡10年发展,应用交付成核心架构
  18. citymaker 8 sketchup和3dsmax直接导出fdb
  19. ch19.PDO。p360---练习三。通过pdo更新数据
  20. Linux input 子系统详解

热门文章

  1. Android麦克风录音的实现
  2. matlab与机器学习(三)以辛烷值含量预测为例BP神经网络(含代码解析)
  3. PID自控理论(频域bode图理论分析)
  4. mysql-5.7.10-winx64安装配置
  5. Silverlight 2.5D “.NET研究”RPG游戏技巧与特效处理:(十二)魔法系统
  6. 怎么用php编写论坛,php编写简单论坛总结
  7. javaweb:在线聊天网站
  8. 【中创算力】第五届优秀员工表彰大会
  9. 真正理解傅里叶级数和傅里叶变换
  10. ChatGPT已接入微软必应Bing搜索?如何进入新必应候补名单抢先体验