基础语法
- 单行和多行注释
-- 这是一条注释
--[[
多行注释
多行注释
--]]
-
建议的命名规则按照:
参数命名规则 n开头代表参数是number t开头代表是table b开头代表是bool -
nil(空)
nil 类型表示一种没有任何有效值,它只有一个值 -- nil,例如打印一个没有赋值的变量,便会输出一个 nil 值
对于全局变量和 table,nil 还有一个"删除"作用,给全局变量或者 table 表里的变量赋一个 nil 值,等同于把它们删掉。lua gc机制会自动定时把这类数据进行回收
nil 作比较时应该加上双引号 ":
在c++中,全局非静态变量可不赋值,也可赋初值,静态全局变量默认赋值为0进行占位,c++中的 NULL 一般表示为0,nullptr 则指代一个空指针,也表示删除的意思
-
boolean(布尔)
boolean 类型只有两个可选值:true(真) 和 false(假),Lua 把 false 和 nil 看作是 false,其他的都为 true,数字 0 也是 true: -
b if a else c a and b or c
模块是什么? 包是什么?
pkage.loaded[moudle_name]
所有加载过的模块都存在这种表里面
pkage.searcher 搜索器中去查找 preload 搜索器 lua搜索器
定义lua搜索器搜寻的路径
require “moudle”
先去已经加载过的模块表中查找
再去4大搜索器中找
lua中的pair 和ipair的区别?
- 顺序遍历(从1开始)(ipair是顺序遍历)
- 碰到nil就停止(ipair)(pair是哈希,碰到nil不停止)
lua的字符串操作?
Lua的字符串操作
点击查看代码
print(string.format("格式化输出字符串%d",123))
str = "abcDEfg"
print("小写转大写"..string.upper(str))
--大写转小写
print("大写转小写"..string.lower(str))
--反转字符串
print("翻转字符串"..string.reverse(str))
--字符串索引查找 索引从1开始
--双返回值 查找字符串的首个字符和末尾字符的索引值
print("字符串索引查找"..string.find(str,"DE"))
--截取字符串 [a,b]双闭
print("截取字符串"..string.sub(str,3,4))
--字符串重复复制 第二个参数重复次数
print("字符串重复复制"..string.rep(str,2))
--字符串修改 参数(字符串,需要修改的字符串,用于替换的字符串)
--返回两个参数,第一个是修改后的字符串 第二个参数是修改的次数
print("字符串修改"..string.gsub(str,"DE","**"))
--字符 转 ASCII码 第二个参数是字符串中指定位置的字符 索引从1开始
a = string.byte("Lua",1) --L的ASCII码
print("L的ASCII码"..a)
--ASCII码转字符
print("ASCII码转字符"..string.char(a))
可变参数与返回值?
--变长参数的使用
--变长参数的使用需要先在函数内部用表存起来再对表进行相关操作
func4 = function(...)
arg = {...}
for i = 1,#arg do
print(arg[i])
end
end
--接收多返回值问题
tmp1,tmp2,tmp3 = func2(1,2,3) --当对应时会依次接收到三个返回值
--当接收参数少于返回值个数 会自动舍弃多余返回值
tmp1 = func2(1,2,3) --只有tmp1会接收到1
--当接收参数多于返回值个数 多余的默认为nil
tmp1,tmp2,tmp3,tmp4 = func2(1,2,3) --tmp4默认为nil
lua如何判空表?
if tbl and next(tbl)!=nil then print("table not nil") end
lua 是怎么实现深浅拷贝的?
点击查看代码
a = 1
b = a -- copy
deepCopyTbl = function (tbl)
copy = function(tbl)
if not tbl and type(tbl) ~= "table" then --先看copy方法中的代码,如果这个类型不是表的话,就没有遍历的必要,可以直接作为返回值赋值;
return tbl;
end
local newTbl = {} --当前传入的变量是表,就新建一个表来存储老表中的数据,下面就是遍历老表,并分别将k,v赋值给新建的这个表,完成赋值后,将老表的元表赋值给新表。
for k,v in ipairs(newTbl) do --在对k,v进行赋值时,同样要调用copy方法来判断一下是不是表,如果是表就要创建一个新表来接收表中的数据,以此类推并接近无限递归。
newTbl[copy(k)] = copy(v)
end
return setmetatable(newTbl,getmetatable(tbl))
end
return copy(tbl)
end
lua中如何实现对表只读?
点击查看代码
--- 强烈注意!!!! 如果你的table改动过元表 将其设为只读以后 在进行深拷贝元表无法继承 只能拷贝其中的值
--- 调用这个函数以后 table内部所有层都会设为保护 如果你想对其重新设为保护则会报错 如果有特殊需求则需要深拷贝这个对象才可以重新设置保护
--- 原生的next会失效 因为其无法调用到_index
function M.readOnly(t)
local locked = {}
if not __G.proxiesCfg[t] then
-- logInfo("新建一个只读的table 调用的位置:",M.print_stack(2))
-- local newt = t
locked = LOC.readOnlyBase(t)
__G.proxiesCfg[t] = locked
else
locked = __G.proxiesCfg[t]
end
return locked
end
end
function LOC.readOnlyBase(t)
for k, v in pairs(t) do
if type(v) == 'table' then
local mt = getmetatable(v)
if mt and mt["__index"] and __G.proxiesCfg[mt["__index"]] then
t[k] = __G.proxiesCfg[mt["__index"]]
else
t[k] = LOC.readOnlyBase(v)
end
end
end
local locked = {}
local mt = {
__index = t,
__len = function()
return #t
end,
__pairs = function(tt)
return function(_, index)
return next(t, index)
end, tt, nil
end,
__newindex = function(t, k, v)
if t[k] then
logError("table数据只读 不允许修改旧值:",k,t[k],table_print(t[k]),table_print(v))
else
logError("table数据只读 不允许添加新值:",k,t[k],table_print(t[k]),table_print(v))
end
local context = "table数据只是可读 不允许修改:"..debug.traceback()
logError(context)
__G.insertTracebackLog(context)
end,
__isReadOnly = true,
}
setmetatable(locked, mt)
return locked
end
lua 中的ipairs 和 pairs区别?
情况一:table组成由 哈希表(键值对,开链解决冲突),数组(数字,表)
那就根据元素类型进行分类,哈希表一组,数组一组,使用ipairs时候打印数组,使用哈希表时候打印全部,数组也当作kv值对进行操作。
情况二:数字和表混合
先哈希表再数值匹配
lua中的元表和元方法?
点击查看代码
-- 对于string number bool基础数据类型
A = {}
B = {}
setmetatable(
A,
{
__index = B, --索引查询
__newindex = B, --索引更新
__add = B, --加法
__sub = B, --减
__mul = B, --乘
__div = B, --除
__mod = B, --取模
__pow = B, --乘幂
__unm = B, --取反
__concat = B, --连接
__len = B, --长度
__eq = B, --相等
__lt = B, --小于
__le = B, --小于等于
__call = B, --执行方法调用
__tostring = B, --字符串输出
__metatable = B --保护元表
}
)
--- 元表元方法的设置
father = {
prop1=2
}
father.__index = father -- 把father的__index方法指向它本身
son = {
prop2=1
}
setmetatable(son, father) --把son的metatable设置为father
print (son.prop1)
--输出结果为2
table的打印
点击查看代码
local M = {}
local tconcat = table.concat
local tinsert = table.insert
local srep = string.rep
M.print_table = function(root)
local cache = { [root] = "." }
local function _dump(t,space,name)
local temp = {}
for k, v in next, t do
local key = tostring(k)
if cache[v] then
tinsert(temp,"+" .. key .. " {" .. cache[v].."}")
elseif type(v) == "table" then
local new_key = name .. "." .. key
cache[v] = new_key
tinsert(temp,"+" .. key .. _dump(v,space .. (next(t,k) and "|" or " " ).. srep(" ",#key),new_key))
else
tinsert(temp,"+" .. key .. " [" .. tostring(v).."]")
end
end
return tconcat(temp,"\n"..space)
end
print(_dump(root, "",""))
end
return M
lua如何实现面向对象
点击查看代码
--[[
模拟继承结构的基类
]]
local _class = {}
function Class(super)
local class_type = {}
class_type.ctor = false
class_type.super = super
class_type.New = function(...)
local obj = {}
do
local create
create = function(c, ...)
if c.super then
create(c.super, ...)
end
if c.ctor then
c.ctor(obj, ...)
end
end
create(class_type, ...)
end
setmetatable(obj, {__index = _class[class_type]})
return obj
end
local vtbl = {}
_class[class_type] = vtbl
setmetatable(
class_type,
{
__newindex = function(t, k, v)
vtbl[k] = v
end,
--For call parent method
__index = vtbl
}
)
if super then
setmetatable(
vtbl,
{
__index = function(t, k)
local ret = _class[super][k]
vtbl[k] = ret
return ret
end
}
)
end
return class_type
end
lua如何实现类?
在Lua中没有直接的类的相关语法,但是可以通过表来模拟继承
在Lua中表模拟类时,表中各元素之间相互独立因而表中方法无法像类一样直接调用其它元素,成员函数想要访问成员变量只能靠传参或传入表后利用表调用成员变量。
传入调用表更为通用,可自行定义一个参数用来接收调用表对象,用普通的点.调用时将表传入进去即可在函数内部利用表对象获取相应的成员变量了。
现实开发更常用冒号配合self完成上述功能。利用 冒号 : 可自动将调用者当作第一个参数传递给函数,在定义函数时采用 冒号:的定义方法 配合self的使用(self默认为函数参数的第一个参数),达到类调用成员变量的效果。
点击查看代码
local ClassDefineMt = {}
--继承基类的函数 如果使用基类存在子类不存在的函数时会去__tbl_Baseclass__寻找并设置
function ClassDefineMt.__index( tbl, key )
local tBaseClass = tbl.__tbl_Baseclass__
for i = 1, #tBaseClass do
local xValue = rawget(tBaseClass[i],key) --查询tBaseClass下面有没有对应的key或者函数
if xValue then
-- print("ClassDefineMt __index:",key)
rawset( tbl, key, xValue ) --设置基类函数到子类table中
return xValue
end
end
end
---允许多个基类
function __G.class( ... )
local ClassDefine = {}
-- 这里是把所有的基类放到 ClassDefine.__tbl_Bseclass__ 里面
ClassDefine.__tbl_Baseclass__ = {}
local arg = {...}
for index = 1, #arg do
local tBaseClass = arg[index]
--将基类存储进__tbl_Baseclass__
table.insert(ClassDefine.__tbl_Baseclass__, tBaseClass)
for i = 1, #tBaseClass.__tbl_Baseclass__ do
--将基类的基类也写入__tbl_Baseclass__中 多重继承
table.insert(ClassDefine.__tbl_Baseclass__, tBaseClass.__tbl_Baseclass__[i])
end
end
-- 所有对实例对象的访问都会访问转到ClassDefine上 设置ClassDefine为元index
local InstanceMt = { __index = ClassDefine } --先调用InstanceMt的__index然后在调用ClassDefine的__index找到对应的函数
-- IsClass 函数提供对象是否某种类型的检测, 支持多重继承
ClassDefine.IsClass = function(self, classtype)
local bIsType = (self == classtype)
if bIsType then
return bIsType
end
for index=1, #self.__tbl_Baseclass__ do
local baseclass = self.__tbl_Baseclass__[index]
bIsType = (baseclass == classtype)
if bIsType then
return bIsType
end
end
return bIsType
end
--构造函数参数的传递,只支持一层, 出于动态语言的特性以及性能的考虑
ClassDefine.new = function( self, ... )
local oNewInstance = {}
oNewInstance.__ClassDefine__ = self -- IsType 函数的支持由此来
oNewInstance.IsClass = function( self, classtype )
return self.__ClassDefine__:IsClass(classtype)
end
-- 这里要放到调用构造函数之前,因为构造函数里面,可能调用基类的成员函数或者成员变量
setmetatable( oNewInstance, InstanceMt )
local funcCtor = rawget(self, 'Ctor')
if funcCtor then
funcCtor(oNewInstance, ... )
end
return oNewInstance
end
setmetatable( ClassDefine, ClassDefineMt ) --设置元索引函数
return ClassDefine
end