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