Lua是一种脚本编程语言,又被称为嵌入式的脚本语言。可以独立运行,也可以作为一个库,嵌入到宿主语言中。宿主语言需要创建Lua虚拟机加载Lua源码文件,虚拟机再将Lua代码转换为中间字节码并执行。
1.第一类值:lua当中函数是一个值,他可以存在变量中,可以作为函数参数,可以作为返回值
2.闭包:通过调用含有一个内部函数加上该外部函数持有的外部局部变量(upvalue)的外部函数(就是工厂)产生的一个实例函数,闭包组成:外部函数+外部函数创建的upvalue+内部函数(闭包函数)
3.pairs与ipair的区别:pairs会遍历table的所有键值对;ipairs就是固定地从key值1开始,下次key累加1进行遍历,如果key对应的value不存在,就停止遍历
4.require、dofile、loadfile的区别:(1).在加载一个.lua文件时,require会先在package.loaded中查找此模块是否存在,如果存在,直接返回模块;如果不存在,则加载模块文件。
(2).dofile读入代码文件并编译执行,每调用dofile一次,都会重新编译执行一次。
(3).loadfile:编译代码,将整个模块文件当成一个函数返回,但是不执行代码,dofile是对loadfile的一次包装。
5.Lua的垃圾回收是自动进行的,但是我们可以collectgarbage方法进行手动回收。
尽量用局部变量,这样当其生命周期结束时,就能被回收;对于全局变量,可以根据使用情况置空,及时回收内存。另外,如果某些情况出现或即将出现内存占用过大的情况,可以考虑手动去进行垃圾回收。
6.Lua性能优化:(1).给table添加元素时,tab[#tab + 1] = a比table.insert(tab, a)效率高,远比table.insert(tab, 1, a)效率高;
(2).以局部变量代替多次使用的外部变量(config.XXX);
(3).减少函数调用可以很大提高效率;
(4).string.format比..效率低很多,但是GC会相对低一点,在大字符串连接中,应避免..。
(5).应用table来模拟buffer,然后concat得到最终字符串;
(6).3R原则:
(Reducing)避免创建新对象和节约内存。例如:如果你的程序中使用了太多的表,你可以考虑换一种数据结构来表示。
(Reusing)如果无法避免创建新对象,我们需要考虑重用旧对象。
(Recycling)Lua的垃圾回收器是一个增量运行的机制,即回收分成许多小步骤(增量的)来进行。频繁的垃圾回收可能会降低程序的运行效率。我们可以通过Lua的collectgarbage函数来控制垃圾回收器。
7.对元表的理解:给一个table关联元表 就是当你访问的这个table所访问的值不存在的时候 会返回默认的元表里的值 可以理解成面向对象里的继承 元表就是它的父类 如果本身有值就用本身的值 没值就用父类的值。
8.弱表:一个表是弱表,仅当
1. 该表有一个元表
2. 元表有成员__mode
3. __mode的取值为"k"或"v"或"kv",依次表示键是弱的,值是弱的或者键值都是弱的。
9.table序列化存储工具类
UserDataClass = Class()
local _table_insert = table.insert
local _tostring = tostring
local _string_format = string.format
local _pairs = pairs
local _type = type
local _table_concat = table.concat
local persistentDataPath = UnityEngine.Application.persistentDataPath
local function split_table(obj,str_tbl)
if not str_tbl then
str_tbl = {}
end
local t = _type(obj)
if t == "number" then
_table_insert(str_tbl, obj)
elseif t == "boolean" then
_table_insert(str_tbl, _tostring(obj))
elseif t == "string" then
_table_insert(str_tbl, _string_format("%q", obj))
elseif t == "table" then
_table_insert(str_tbl, "{\n")
for k, v in _pairs(obj) do
_table_insert(str_tbl, "[")
split_table(k,str_tbl)
_table_insert(str_tbl, "]=")
split_table(v,str_tbl)
_table_insert(str_tbl,",\n")
end
_table_insert(str_tbl, "}")
elseif t == "nil" then
return nil
else
error("can not serialize a " .. t .. " type.")
end
return str_tbl
end
function UserDataClass:_init(path)
if not path then
error("path is nil")
return
end
self.path = persistentDataPath .."/"..path
self.file = io.open(self.path,"r+")
if self.file then
local content = self.file:read("*a")
self.data = self:UnSerialize(content)
else
self.file = io.open(self.path,"w+")
end
self.data = self.data or {}
end
function UserDataClass:_delete()
self.file:close()
self.path = nil
self.data = nil
self.file = nil
end
function UserDataClass:SetValue(key,info)
self.data[key] = info
end
function UserDataClass:SaveFile()
if self.file then
self.file:seek("set")
if self.file:write(self:Serialize(self.data)) == nil then
return
end
self.file:flush()
else
print("file is not exist")
end
end
function UserDataClass:GetValue(key)
return self.data[key]
end
function UserDataClass:Serialize(obj)
local t = split_table(obj)
return _table_concat(t)
end
function UserDataClass:UnSerialize(lua)
local t = _type(lua)
if t == "nil" or lua == "" then
return nil
elseif t == "number" or t == "string" or t == "boolean" then
lua = _tostring(lua)
else
error("can not unserialize a " .. t .. " type.")
end
lua = "return " .. lua
local func = load(lua)
if func ~= nil then
return func()
end
end
10.Lua配置表存储优化思路:配置表中大量的数据是重复的,或着是代表没有意义的空值(比如0,[]等);大量的中文字符串是需要游戏后期做本地化处理的;很多复合型数据(子表,数组)内容是一样的。优化方案:1.对于Excel中的一列,出现次数最多的值认定为默认值,然后把它从Lua表中剔除掉,然后利用metatable机制实现全局默认值存储;2.对于中文字符串,替换为一个唯一的id标识,写回到Lua表中,读取的时候加上相应的查找替换;3.对于一些复杂的子表或着数组,做唯一化替换处理,替换后写回到原始数据中;
12. Lua字符串存储:1.Lua中通过字符串的hash值来对字符串进行查找。2.Lua中的字符串变量存放的是字符串的引用,而不是字符串本身。3.同一个字符串在Lua虚拟机中只有一份。4.Lua虚拟机中global_State的strt字段存放着当前系统中的所有字符串。5.尽量避免循环拼接字符串,每拼接一次要创建一个新的字符串。
13.Lua多线程:单个 Lua 虚拟机只能工作在一个线程下,比较成熟的Lua多线程库有Lanes和Effilm,允许用户在不同的虚拟机间相互调用函数,大约是利用在虚拟机间同步函数的字节码和 upvalue 实现的。
14.Lua与C#交互主要是由Lua官方的提供的开源项目LuaInterface实现的,项目中提供了由C写的库文件,依靠C作为中间语言,维护一个虚拟栈,通过虚拟栈来实现数据交互,Slua/Ulua等基本都是借鉴LuaInterface库实现的。C#调用Lua需创建一个Lua虚拟机对象,虚拟机加载Lua文件并将其转换为字节执行。Lua调用C#需将C#源文件生成对应的Wrap文件,运行时Wrap文件会把C#方法字段注册到Lua虚拟机中,供Lua调用。
15.Lua协程拥有自己的独立的栈,局部变量,和指令; 所有协程都可以共享全局变量;协程不能像线程那样并行执行,协程之间需要相互协调执行,同一个时刻只能运行一个协程;Lua协程的实现