

























创建于 2025年3月4日 17:41:22 · 约2,399字
安装不多说去看文档。在IDEA中使用emmylua插件支持lua(settings->Editor->FileType->luaLanguage虽然里面已经添加了一个*.lua.txt但是不管用再加一个一模一样的就管用了)
安装
在文件开头加入#!/usr/local/bin/lua就可以像执行shell一样去执行lua
动态,弱类型语言, 在默认情况下,变量总是认为是全局的。全局变量不需要声明,哪怕是语句块或是函数里,除非用local 显式声明局部变量,否则全是全局的。
在实践中,建议给所有变量加上local,除非你确认一定需要全局变量。不加local所造成的奇怪bug会让你终身难忘,而且local更会快
给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil如果想删除一个全局变量,只需要将变量赋值为nil
只有nil和false是假;0也是真
从1开始的下标(?从其他语言取的时候一定要注意 一般约定,以下划线开头连接遗传大写字母的名字(比如 _VERSION)是Lua内部全局变量的保留字
本身有JIT速度还可以,和其他语言交互比较慢。
lua语法老严格了,最好按照强迫症风格来写,lua是纯解释,被调用的必须要比调用者先声明。 Lua是运行在一个单线程虚拟机上运行所以只有单线程
userdata是和其他语言交互的核心,存储任意C的数据结构;table看你存什么,它相当于把数组和字典混合了起来,底层用哈希表还是顺序表看心情(看你存啥他自己转换
对字符串进行算数操作,Lua会尝试类型转换为数字然后操作,转不了就报错(?
lua
a,b,c=1 -- 1,nil,nil 多的就nil
a=1,2,3 -- 1 少了就扔
type(x)==nil -- false 因为返回的是"nil"
type(x)=="nil" -- 这回对了
x~=nil -- 不等于也很奇葩
"2" + 6=8.0 -- 神奇.
6 .. 8=68 -- 注意返回的是数字 用 .. 的时候必须要有空格t.i和t[i]本质都是函数调用,类似于getattr__eq或超过阈值才会触发rehash,hash会重新计算一遍key插入新表[1, t->asize]外的数都会被存放在hash部分,rehash的时候会重新计算是不是放入array部分合适t={nil,nil,nil},如果过于稀疏了array部分甚至会收缩for k,v in pairs(t) do统计(有点笨__mode="k"此时如果key被删除了,那么table也会移除这个k-vlua
local M={}
funciton M.func1() end -- 这样就可以在外面调用
return M -- 结束
local M = require("moduletest") -- 在另一个文件中获得M调用函数即可多文件其实和单文件一模一样,非local修饰就对全局空间赋予变量操作, local修饰是表示在当前作用域中是本地的,在函数里面声明就限制在函数里。
package.loaded中注册此module,热更新原理就是把它置为nil然后重新require替换掉 function M:test() end 相当于带了个py中的self进去,而且调用的时候不能混着调用,:定义就:调用点的就点调用。function M.test(n, ...) local args={...} end 这样就拿到了可变参数,都是按照自然数索引传的元表,相当于py中的魔术方法,可重载的函数也是有限的。把元表指定给某个表后,相当于为该表添加了特定的重载行为。
两个变量里面都没有发现对应的行为就会报错,行为会优先调用元表的方法没有再调原生,再没有就报错
经典示例两表合并重载加运算符
get/setmetatable获取或者设置某table的元表,拿到就可以修改他原先元表的行为_G设置metatable重载__newindex __index 可以阻止团队里滥用全局变量lua
local mt={}
mt.__add=function(t1,t2) -- +的重载函数
local temp={}
for _,v in pairs(t1)do table.insert(temp,v)end
for _,v in pairs(t2)do table.insert(temp,v)end
return temp
end
local t1={1,2,3}
local t2={2}
setmetatable(t1,mt)
local t3=t1+t2
local st="{"
for _,v in pairs(t3)do st=st..v.."," end
st=st.."}"
print(st)
-- {1,2,3,2,}看一下协程基本就是yield那一套,可以暂停函数的执行
常用深拷贝
lua
function deepCopy(object)
local lookup_table = {} -- 创建一个查找表,用于存储已经复制过的对象,避免循环引用。
local function _copy(object)
if type(object) ~= "table" then -- 如果对象不是表,则直接返回该对象。
return object
end
if 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)
end
setmetatable(new_table, getmetatable(object)) -- 设置新表的metatable为原表的metatable,确保元方法等特性也被复制。
return new_table -- 返回新创建的表。
end
return _copy(object) -- 调用内部复制函数,开始复制过程。
end实现简单的面向对象 看好他的表,利用表的重载方法和metatable, 实现类似于OOP的东西(有点过于灵活了
lua的闭包和其他语言闭包一样,也是函数里面套函数,内部的函数引用的资源内存调用栈变量等都会存放起来,upvalue就是指向引用外部变量的指针,循环upvalue linked list查找,创建的时候标open用完了就置为close,下次GC就删掉。
整个lua就是被包在function main (...)中,所以所有的函数实际上都是闭包,同理函数upvalue一开始就是指向全局栈,当被当作闭包返回才会指向指向upvalue linked list。
lua的GC使用标记-删除法,分代回收新申请的更容易被扫描,lua虚拟机提供了collectgarbage函数手动回收,但是一般不用。GC八股看一下
但是小心在lua引用的C#对象如果一直不释放就会导致内存泄漏
[ ⚠️Warning ]
热更代码中old_module已经在运行产生的数据变化和变量等不会被影响吗,热更新被替换的函数,万一还有正在运行的不久有问题了吗。我看市面上的解决方法是让玩家退出然后重新进游戏,是不是就是说重新运行游戏相当于lua虚拟机重启了重新加载了一次
gpt
## 为什么游戏要求重新登录?
你的理解完全正确! 重新登录 = Lua虚拟机重启 = 完全重新加载
### 重启的好处:
1. 状态清理 :所有变量、连接、缓存都重新初始化
2. 避免版本混乱 :不会出现新旧代码混合执行的情况
3. 内存清理 :避免内存泄漏和垃圾数据
4. 确保一致性 :所有模块都是同一版本
## 真正的热更新挑战
### 安全的热更新需要:
1. 状态迁移机制 :保存关键数据,更新后恢复
2. 版本兼容性检查 :确保数据结构兼容
3. 执行时机控制 :在安全的时间点进行更新
4. 回滚机制 :更新失败时能够恢复
### 实际应用中的策略:
- 配置热更 :只更新配置数据,相对安全
- 功能热更 :只在特定安全点(如玩家空闲时)进行
- 分模块更新 :只更新独立性强的模块
- 灰度更新 :先在少数玩家上测试
所以你看到的"要求重新登录"确实是最稳妥的方案,避免了热更新的各种风险。真正的无缝热更新技术门槛很高,需要精心设计的架构支持。lua和C#在交互的时候值类型也可能会因为拆装箱产生GC。 lua中的字符串分长短字符串40个为界,短字符串创建的时候就计算好了hash如果再创建或者调用相同的字符串会指向同一个,长字符串则每次都重新创建并设置GC相关,而且是用到的时候才赋值。
luaGC完了会 整理内存碎片 执行finalizer析构 更新弱引用 不太明白或者不太熟的有 为什么值传递有GC
Lua的GC机制
C#调用Lua细节
实现简单的面向对象
作为一门副语言够用就行,在这整理遇到的坑
lua在unity中不会被识别为资源文件,所以要改名为script.lua.txt这种后缀
在Rider中安装
#todo Rider使用EmmyLua代码提示
GitHub - CppCXY/EmmyLua-Unity-LS
忽略 EmmyLua 调试代码 - 狂飙
使用Xlua的套路
lua
-- 一个面板一个表
BagPanel={}
-- 面板自身对象
BagPanel.panelObj=nil;
-- 面板上的对象
BagPanel.CloseButton=nil
BagPanel.EquiToggl=nil
BagPanel.ItemToggle=nil
BagPanel.GemToggle=nil
-- 成员方法
function BagPanel:Init() -- 初始化
if self.panelObj == nil then
--实例化面板
--拿控件
--绑定事件
end
end
-- 显隐方法
function BagPanel:ShowMe()
self:Init()
self.panelObj:SetActive(true)
end
function BagPanel:HideMe()
self.panelObj:SetActive(false)
end在Lua中TMP使用的应该是TMPro.TextMeshProUGUI和Csharp中不一样
Xlua和AB打包有冲突,需要先清Xlua的ClearGenerateCode再打包。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。