Lua 是一种由C编写的解释性脚本语言。编程
local
修饰则为局部变量,仅在当前块中有效,事后自动释放。local
修饰则为全局变量,直接进入_G
_ENV
等全局数组中。类型 | 示例 | 备注 |
---|---|---|
nil | x=nil |
nil 就是null |
boolean | x=false |
nil,false=false ,true,非nil=true |
number | x=1 y=1.2 |
number自适应于整型、浮点型 |
string | x='str' |
字符串类型,无字符类型 |
function | x=function()end |
函数亦是基本的变量类型 |
coroutine | 协程类型 | |
userdata | C/C++ 数据类型 | |
table | x={} |
lua 核心数据结构 |
------------------------------------- -- 两种方式定义函数,效果同样 local function def() -- 栈式返回值 return true,'hello world' end local def = function() return true,'hello world' end -- 栈式赋值 local a,b = def() -- 二元赋值 local a = 0 or 1 -- 此时 a 为 0 local a = nil or 1 -- 此时 a 为 1 -- 三元赋值 local a = true and 1 or 0 -- a 为 1 local a = false and 1 or 0 -- a 为 0 -- 最多见的方法 a = tostring(123456) a = tonumber("123456") a = type(a)
-- base定义 str = 'hello world' -- 经常使用定义,内部可携带:单引号且不用转义 str = "hello'-'world" -- 多行字符串 str = [[ hello world! ]] -- 字符串长度 print(string.len("str"),#str) -- 字符串链接 print('hello '..'world') -- 大小写转化 string.upper(a) string.lower(a) -- char ==> string string.char() -- string ==> char string.byte() -- 截取字串 string.sub(str,[start],[end]) -- 查找字串位置 string.find(str,sub_str,[start],[end]) -- % 占位符格式化字符串,%d数字 %s 字符串 %% % string.format("hello %s %d","word",123)
-- 数组定义方式 local x = {1,2,3,'4'} -- 数组类型:table,实际并不是如此 print(type(x)) -- 数组、字符串的下标都从 1 开始 print(#x, #'hello', x[1]) -- 数组新增 table.insert(x,1,10) -- 数组删除某项值 table.remove(x,1) -- 链接大量字符串,消耗少,速度快 table.concat(x,"-")
~ | 传递 | 复制 |
---|---|---|
基础类型 | 值传递 | 深复制 |
引用类型 | 引用传递 | 浅复制 |
local num = 100 local tmp = { a = 100, b = 120 } -- 此时执行 值传递 dat = num, dat = tmp.a -- 此时执行 引用传递 local test = tmp -- 弱引用 local tmp = {} -- key,弱引用 setmetatable(tmp, { _mode = "k" }) -- value,弱引用 setmetatable(tmp, { _mode = "v" }) -- key-value, 弱引用 setmetatable(tmp, { _mode = "kv" })
table
数组以及表,内存是一致的,表须要遍历,数组可直接定位。~ | pairs |
ipairs |
---|---|---|
迭代时遇到nil |
跳过本次 | 中止迭代 |
x = {1,nil,3,4} -- 1 for _,v in pairs(x) do print(v) end -- 1 3 4 for _,v in ipairs(x) do print(v) end
-- 基本定义方式 local p = { a=10, b=20 } -- 索引命中方式 print(p["a"], p.a) -- 新增索引项 p.c = 100 -- 字符串索引,任意合法的字符串均可以做为键 p[" "] = 123456 -- 映射:将内存数值映为可读字段 local state = { login = 1, logoff = 0 }
-- index 元表 local tmp = { x=1, y=2 } setmetatable( tmp, { __index = { z = 10 }}) -- 另外一种方式 local tmp = setmetatable({x=1,y=2},{__index={z=10}}) -- 索引为nil或不在原始表中,则会在附表中查找 print(tmp.x, tmp.y) -- newindex local tmp = { x=1, y=2 } setmetetable( tmp, { __newindex=function(tab,key,val) -- 此处可不执行,用以锁定 table rawset(tab,key,'val:'..str(val)) end }) -- 新增索引,执行newindex方法 -- y = 'val:100' tmp.y = 100 -- 此时y已存在,不执行newindex -- y = 100 tmp.y = 100 -- rawget 获取表中 key(字符串) value local dat = rawget(tab,"key") -- 设置表 tab,key(字符串) val rawset(tab,key,val)
-- 异步回调 local function demo(args, fun) print("function demo is running") fun(args) end -- 将匿名函数作为参数传递至原方法内部 demo("hello world", function(args) print(args) end) -- 闭包函数 local function demo(args) -- 闭包函数返回后, args参数不会被释放 return function() print(args) end end demo("hello world")
1. 算术运算 + - * / // % ^ -- / 除法运算 // 整除运算 2. 关系运算 == ~= > >= < <= 3. 逻辑运算 and or not 4. others . [] () {} , : # .. =
-- 顺序判断 if true then print(true) elseif true then print(true) else print(false) end -- 经常使用判断 if true then print(true) end
-------------------------------------------- -- lua没有 `switch` 选择循环 -- lua没有` continue`退出,仅存在 `break`退出块。 -- while循环 while(true) do print(true) break end -- repeat循环,true为退出条件 repeat print(false) until false ------------------------------------------- -- for 头部默认为内部块变量,执行完毕自动释放 -- start stop step for i = 0,10,1 do print(i) end -- k为索引,v为值,同时适配与表格和数组 for k,v in pairs(tab) do print(k,'--',v) end -------------------------------------------- -- for 头部亦可引用外部变量 local i for i = 0,10,1 do print(i) end local k,v for k,v in pairs(tab) do print(k,'--',v) end -------------------------------------------- -- _ 虚变量引用 for _,v in pairs(tab) do print(v) end
-- 若此处为false,程序中断并抛异常 assert(1 == 1) -- 以保护模式执行某方法,程序不会中断 local ok,err = pcall(demo()) local function demo(x,y) print(x/y) end -- 以保护模式执行 demo,参数在其后,成功返回true,失败返回 false,err local ok, err = pcall(demo, 10,5) print(ok,err) local function print_err() print(debug.traceback()) end -- 执行 demo,出错执行 print_end,参数在其后 xpcall(demo,print_err(),0,10)
lua 面向对象是一种伪对象,实际是一个衍生的索引表。数组
- 模块:块私有变量或方法仅模块内部生效,外部没法使用
- 类: class仅可读写全部
.
级的方法以及变量。- 对象:obj仅可读写全部
self
级的变量以及方法,仅可读全部.
级变量以及方法,强写class级变量实际是新建一个obj级变量,对整个class并不生效。
模块,类,对象之间的读写应该分离以避免出现系统性error,全部超出限度的强写实际都是新建一个当前等级的变量,原始上一级变量并未发生改变。数据结构
模块 | 类 | 对象 | |
---|---|---|---|
模块 | 读写 | ||
类 | 读 | 读写 | |
对象 | 读 | 读 | 读写 |
-- class -------------------------------------------- local class = {} -- 模块私有方法,仅仅块内生效 local function example() print("example") end -- 能够看做类变量 class.size = 100 -- 能够看做类方法 function class.print_size() print(class.size) end -- 类new对象的方法 function class:new(x,y) cla = {} -- 对象变量 cla.x = x or 1 cla.y = y or 2 setmetatable(cla,{__index=self}) return cla end -- 对象方法 function class:print() print(self.x,self.y) end return class ------------------------------------------------- -- obj -- 引用块 local class = require("example") -- class访问 class.print_size() -- obj 访问 local obj = class:new(10,20) -- obj -> class 访问 obj.print_size()
面向切面编程是一种特殊的设计方式,面向对象的主要目的是为了代码复用,面向切面则是一种函数结构化方法。闭包
-- 状态码 local STATE = { PREPARE = 0, FIGHT = 1, REWARD = 2, REFRESH = 3, } -- 主方法 local function running = {} running[STATE.PREPARE] = function(comp) -- pass end running[STATE.FIGHT] = function(comp) -- pass end running[STATE.REWARD] = function(comp) -- pass end running[STATE.REFRESH] = function(comp) -- pass end -- running 主程序 while(true) do running[comp.state](comp) end
_G
_ENV
中。-- lua 模块加载的基本路径 local path = package.path -- lua 检测模块是否已加载 if package.loaded["exp"] then print("exp 模块已加载!") end -- lua 热更新指定模块 local function hotfix(file) if package.loaded[file] then package.loaded[file] = nil end require(file) end -------------------------------------------- local x = require("x") -- 先扫描 require("x")路径 -- 查找须要被加载的路径是否已经被加载 -- 若模块未被加载,则加载模块,并返回索引 -- 若模块已被加载,则直接返回索引 -- 加载某路径下的文件,并执行 -- 执行语句则,加载编译,执行 dofile("luafile.lua") -- 加载指定文件,封装为一个函数返回 -- 索引仅需加载一次 local load = loadfile("luafile.lua") -------------------------------------------- -- 弱类型,编译解释 -- 全部变量,在第一次被加载的时候,会被肯定下来 -- 加载时,会将代码编译为机器码,而后给解释器 -- 之后执行时,皆使用加载时的配置类型 local y = 100 -- 编译时肯定为 int local s = 'he' -- 编译时肯定为 string
local exp = require("example") local ret = {} -- 被预加载后,进入内存,但仅可局部使用 local inner = "inner value" local function inner_fun() print("hello world\n") end -- 被预加载后,进入内存,外部亦可以使用 ret.outer = "outer value" function ret.out_fun() print("hello world\n") end -- 预加载时 -- function 内的语句块会进入内存 -- function 外的语句块会执行一次,但不进入内存 print(inner) inner_fun() -- return 模块 -- 语句块会被执行一次,而后丢弃 -- 全部成员所有会被加载进入内存 -- 若成员被local修饰则非本模块对象没法访问 return ret
local
变量会自动释放,var=nil
亦可释放内存。_G
_ENV
这两个内部存储全局变量。collectgarbage()
GC管理。local x = 100 local y = { a=100, b=200 } z = 100 -- 不推荐使用全局变量 if _G["z"] then print("global var z"..z) end -- 释放全局变量 y = nil -- 释放局部变量 x = nil -- 释放table内变量 y.a = nil -- 执行一次 GC collectbardage("collect") -- 计算当前程序所占总内存 local num = collectgarbage("count"); -- 慎用,解释器中止自动GC,必须手动处理,不然内存会爆炸 collectbardage("stop")
记录一些经常使用的,易遗忘的方法以及小技巧。异步
local file = io.open(".../example.txt","w") -- 读写外加参数便可 local str = file:read() file:write("hellow world") -- 关闭文件 io.close(file) file:close()
协程管理模块化
协程与线程 https://blog.csdn.net/jason_cuijiahui/article/details/82587076函数
lua 协程仍是单线程工做,只是同一时间里只有一个协程在工做,且是守护线程。
拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。性能
-- 线程总得是无限循环的方法 local function done(dat) while() print(dat) end -- 协程执行至此处则 dead end -- 建立协程 suspended 挂起状态 local cor = coroutine.create(done) -- 获取指定协程的现行状态 dead,suspended,running print(coroutine.status(cor)) -- 重启或开启协程,协程引用,外加参数(没有能够不加) running coroutine.resume(cor,"hellow world") -- 挂起当前正在运行的协程,并使得协程返回数据 dat,协程最多只有一个能够运行 coroutine.yield(dat) -- 返回某个正在running 的协程的线程ID coroutine.running()
生产者消费者模型测试
1.coroutine.resume(cor) :开启协程等待返回值 status,valueui
2.coroutine.yield(dat) :挂起运行协程返回 dat
-- 弱类型语言的好处 local produce -- 暂停程序 1 秒,获取信息 local function step() os.execute("sleep 1") print(coroutine.running()) print(coroutine.status(produce)) end -- 生产者模型 local function productor() local i = 0 while true do step() i = i + 1 -- 挂起当前协程,并返回 i coroutine.yield(i) end end -- 消费者模型 local function consumer() while true do local status,value = coroutine.resume(produce) step() print(status,"--",value) end end produce = coroutine.create(productor) consumer()
不须要解释,容易忘记的东西。
-- 执行系统cmd os.execute("sleep 1") -- 输出 格式化日期 2020-01-01 01:02:56 print(os.date("%Y-%m-%d %H:%M:%S")) -- 输出当前时间戳 print(os.time()) -- 输出程序已经执行的时间 print(os.clock()) -- 将表转化为字符串 local function tostr(tab) local str = "{ " str = str.."\n" for k, v in pairs(tab) do if type(v) ~= "table" then str = str.."[\""..k.."\"]" str = str..":" str = str..v str = str.."," str = str.."\n" else str = str.."[\""..k.."\"]" str = str..":" str = str..tostr(v) str = str.."," str = str.."\n" end end str = string.sub(str, 1, -3) str = str.."\n" str = str .." }" return str end
一些通用性的程序设计。
-- 模块尽可能使用,if return if true then return "err" end -- 方法不变,选择不一样的参数执行 local function execute(param) print(param) end -- 参数不变,选择不一样的方法执行 local Execute = {} Execute[CODE] = function(param) print(param) end
-- 程序设计时,根据实际的
-- 执行所用CPU时长 local begin = os.clock() -- 获取CPU时间戳 local beginTime = os.time() print("hello world") local over = os.clock() local overTime = os.time() -- 0.001212 0.001234 number print(begin, over, type(over)) -- 1596786393 1596786393 number print(beginTime, overTime, type(overTime))
table
,遇到nil
会退出。table
,遇到nil
则会跳过,当迭表明时是乱序的。local tab = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } -- 0.038 ms, 此处 #tab 会一直执行,故必然拖慢速度 for i = 1, #tab do print(tab[i]) end -- 0.030 ms local len = #tab for i = 1, len do print(tab[i]) end -- 0.035 ms for _,val in pairs(tab) do print(val) end -- 0.043 ms for _,val in ipairs(tab) do print(val) end -- 遍历基础数组,速度并没有太多差别 local tab = { a = 1, b = 2, c = 3, d = 4, e = 5, f = 6, g = 7, h = 8, i = 9, j = 10 } -- paris 迭代 数组、表格 -- pairs 迭表明格时,顺序为随机序列 for k, v pairs(tab) do print(k, v) end