lua簡介
C++底層核心模組,暴露核心介面給lua指令碼層,網路的收發都在c++層完成,本書簡述lua直譯器的實現原理,工業級指令碼語言
特性:簡潔高效可移植可嵌入可擴充套件
純C編寫
Lua的資料結構、Lua虛擬機器、Lua的其他內容
我缺少的知識:詞法分析、語法分析、遞迴下降分析、BNF規則
Lua程式碼是解釋成lua虛擬機器能識別的位元組碼而執行的
- 翻譯成位元組碼
- 位元組碼裝載到虛擬機器執行
Lua是有宿主系統的
Lua採用一種通用的資料型別來表示所有的型別,Lua只有字串和表兩種基本的資料結構
一種通用的資料型別:lua_TValue
- 一個欄位儲存資料型別
- 儲存不同的資料型別的資料(聯合體)
commonHeader+union,lua還要標出處理GC的物件
配圖:
字串
每當建立字串時,會先查詢記憶體中是否有一份相同的字串資料,如果存在就直接複用,將引用直接指向字串資料,否則就重新建立一份資料,這樣在進行字串資料比較和查詢時效能會提升不少,系統內部維護了一個全域性的字串的表用來存放字串(LUA虛擬機器使用一個雜湊桶來管理,global_state的strt),比較時可以直接比較字串雜湊值,這樣也是有空間優化,相同字串只有一份資料
應當儘量少的使用字串連線符,每次使用都會建立一個新的字串,大量重複的相同字元連線可以用一個table緩衝區一個字元一個字元的快取起來,然後再呼叫table.concat將其全部連線
Table
有陣列和雜湊表部分,唯一的要求就鍵值不能為nil
陣列從1開始索引,內涵雜湊桶陣列起點和終點的指標還有元表,意思0和負數的索引都是雜湊表裡的內容,如果數字的很大,超過了陣列長度則是在雜湊表裡面存
存的資料有可能在陣列或者在雜湊表部分
查詢資料:使用key來查詢。我們看這個key是否為正整數且他是否大於0且小於等於陣列長度,在則在陣列中查詢,不在則跑到雜湊表去查
設定資料:set setnum setstr三個set資料的函式先找對應的key,找不到則內部是呼叫一個newkey函式分配一個新key,大小不夠會重新雜湊
個人實踐規律:取長度符號#
取長度,只對表的序列部分進行,序列指的是表的一個子集,
當既有陣列部分又有雜湊表部分,優先取陣列部分長度,
當只有陣列部分時候取陣列的長度
(#{1,2,3,nil,4,5,6,} == 6)
當雜湊表的key和陣列的Index一致的時候,遇到[num] = nil的時候便停止計數
(#{[1] = 10,[2]=20,[3]=nil,[4]=60} ==2)
(#{[1] = 10,[2]=20,[3]=32,[5]=60} ==3) 缺少4
當只有雜湊表部分時,取key從1開始的最大正整數
(#{["asd"] = 10,["sd1"]=20,["aasd"]=nil,[45]=60} == 0)
(#{["asd"] = 10,["sd1"]=20,["aasd"]=nil,[1]=60,[2]=899} == 0)
一般要規避重新雜湊操作,一般通過只使用陣列部分、預分配等方式來避免重新雜湊
儘量不要混用陣列和雜湊表部分,一個table最好只放一類資料
lua實現一個佇列
網上的版本,用起來,pushright存資料會往陣列裡的填很多東西,pushleft突破了0,會往雜湊表裡填東西,如果一直popleft多了則陣列部分的頭部會被回收嗎?推測不會,陣列部分的指標指向的陣列整體,前面幾個元素回收了頭部會改變,如果是popright回收陣列部分是可以理解的,如果pop的是雜湊的部分應該是可以回收的
List = {}
function List.new ()
return {first = 0, last = -1}
end
function List.pushleft (list, value)
local first = list.first - 1
list.first = first
list[first] = value
end
function List.pushright (list, value)
local last = list.last + 1
list.last = last
list[last] = value
end
function List.popleft (list)
local first = list.first
if first > list.last then error("list is empty") end
local value = list[first]
list[first] = nil -- to allow garbage collection
list.first = first + 1
return value
end
function List.popright (list)
local last = list.last
if list.first > last then error("list is empty") end
local value = list[last]
list[last] = nil -- to allow garbage collection
list.last = last - 1
return value
end
插入、刪除時間複雜度 O(1),空間複雜度可能會隨著訊息變大而變大,O(n)
使用Insert和Remove的版本,空間複雜度是O(1)的,時間複雜度是(n)
關於清空lua table
a = {1,2,3,4,5}
function upDate(t)
print("====")
print(t)
t = {}
print(t)
end
upDate(a)
print(a)
print(a[1])
這裡設定t = {} 或者 t = nil都不會真的清空table物件 a
只是處理了變數和值之間的關係,t的地址是值傳遞的,嘗試用一個新表的地址給它賦值會出現函式引數值傳遞,對地址t引用的實際值並不會有影響,但是通過t改動引用table裡的實際值是會對a有影響的比如t[1]=999,這裡就是通過地址改動到了實際值的區域
我的方法是使用——table套table,其實就是相當於指標的指標
local a = {1,2,3,4,5}
local b = {9,99,999,9999}
function upDate(t)
print("====")
print(t.a)
t.a = nil
--a = nil
print(t.a)
end
local ta ={}
ta.a = a
upDate(ta)
print(ta.a)
print(a)
這樣子ta.a可以便可以正確的賦值為nil了
我實現的一份LuaQueue程式碼
local LuaQueue = {}
-- pure array table, if you want to iterate use lua "ipairs"
function LuaQueue.New()
return {_length = 0,_maxLength=10,_queue={}}
end
function LuaQueue.SetMaxLength(queue,length)
if(queue==nil) then
error("Queue is nil")
end
queue._maxLength = length
end
function LuaQueue.GetLength(queue)
if(queue==nil) then
error("Queue is nil")
end
return queue._length
end
--push in array last pos O(1)
function LuaQueue.Push(queue,val)
if(queue==nil) then
error("Queue is nil")
end
if(queue._length<queue._maxLength) then
table.insert(queue._queue,val)
queue._length = queue._length+1
else
error("Already reach last pos")
end
end
--O(n)
function LuaQueue.Pop(queue)
if(queue==nil) then
error("Queue is nil")
end
if(queue._length>0) then
table.remove(queue._queue,1)
queue._length = queue._length-1
else
error("Queue is Empty")
end
end
function LuaQueue.GetData(queue)
if(queue==nil) then
error("Queue is nil")
end
local data={}
if(queue._length>0) then
for _,v in ipairs(queue._queue) do
table.insert(data,v)
end
return data
else
print("Queue is Empty")
end
end
function LuaQueue.ClearData(queue)
if queue == nil then
error("Queue is nil")
end
queue._queue = {}
queue._length = 0
end
--[[Example:
local testQueue = LuaQueue.New()
LuaQueue.Push(testQueue,10)
LuaQueue.Push(testQueue,20)
LuaQueue.Push(testQueue,30)
LuaQueue.Push(testQueue,40)
local data = LuaQueue.GetData(testQueue)
for _,v in pairs(data) do
print(v)
end
print("-------------------------------------")
LuaQueue.Pop(testQueue)
local data = LuaQueue.GetData(testQueue)
for _,v in pairs(data) do
print(v)
end
print("-------------------------------------")
LuaQueue.Pop(testQueue)
LuaQueue.Push(testQueue,909)
local data = LuaQueue.GetData(testQueue)
for _,v in pairs(data) do
print(v)
end
LuaQueue.ClearData(testQueue)
--]]