1、注釋
1.1 單行注釋
--注釋內容
--單行注釋 print打印函數
1.2 多行注釋,三種方式
--[[注釋內容]]
--[[注釋內容]]--
--[[注釋內容--]]
--[[
多行
注釋
]]--[[
第二種多行注釋
1
2
]]----[[
第三種
多行
注釋
--]]
2、簡單變量
2.1 聲明變量,所有的變量申明都不需要申明變量類型它會自動判斷類型
a = nil
a = 1
a = 1.2
a = '123'
2.2?nil,有點類似 C#中的null
a = nil
print(a)
2.3?number,所有的數值都是number
a = 1
print(a)
print(type(a))
a = 1.2
print(a)
print(type(a))
2.4 string,字符串的聲明 使用單引號或者雙引號包裹
a = '123'
b = "456"
2.5 boolean
a = true
print(a)
print(type(a))
a = false
print(a)
print(type(a))
3、string字符串相關介紹
3.1 獲取字符串長度
#字符串
s = "aBcdEfg字符串"
s = "字"
--一個漢字占3個長度
--英文字符 占一個長度
print(#s)
3.2?字符串多行打印,lua中也是支持轉義字符的
print("123\n123")s = [[
我是
好人
不要打我
]]
print(s)
3.3?字符串拼接
使用 .. 拼接
--字符串拼接 通過..
print("123".."456")
s1 = "123123"
s2 = 2222
print(s1..s2)
使用方法string.fomat()
print(string.format("我是一個好人,今年%d歲了", 188))
--%d 與數字拼接
--%a 與任何字符拼接
--%s 與字符配對
--.....
3.4?別的類型轉字符串,使用方法tostring
a = true
print(tostring(a))
3.5?字符串提供的公共方法
--小寫轉大寫的方法
print(string.upper(str))
print(str)
--大寫轉小寫
print(string.lower(str))
--翻轉字符串
print(string.reverse(str))
--字符串索引查找
print(string.find(str, "De"))
--截取字符串
print(string.sub(str, 3, 4))
--字符串重復
print(string.rep(str, 2))
--字符串修改
print(string.gsub(str, "De", "**"))--字符轉 ASCII碼
a = string.byte("Llua", 1)
print(a)
a = string.byte("Llua", 2)
print(a)
--ASCII碼 轉字符
print(string.char(a))
4、運算符
4.1?算數運算符
- + - * / % ^
- 沒有自增自減 ++ --
- 沒有復合運算符 += -= /= *= %=
- 字符串 可以進行 算數運算符操作 會自動轉成number
print("加法運算" .. 1 + 2)
a = 1
b = 2
print(1 + 2)
print("123" + 1)
print("123" + "2")print("減法運算" .. 1 - 2)
print("123.4" - 1)print("乘法運算" .. 2 * 3)
print("2" * 4)print("除法運算" .. 4 / 2)
print("1" / 3)print("取余運算" .. 3 % 2)
print("123.4" % 2)--^ lua中 該符號 是冪運算符號
print("冪運算" .. 2 ^ 2)
print(2 ^ 4)
4.2?條件運算符
> < >= <= == ~=
-- > < >= <= == ~=
print(3>1)
print(3<1)
print(3>=1)
print(3<=1)
print(3==1)
print(3~=1)
--不等于 是 ~=
4.3?邏輯運算符
C#規則?&& || ! “短路”
lua對應中?and or not lua中 也遵循邏輯運算的“短路”規則
--&& || ! “短路”
--and or not lua中 也遵循邏輯運算的“短路”規則
print(true and false)
print(true and true)print(false or false)
print(true or false)print(not true)print(false and print("123"))
print(true or print("456"))
4.4?位運算符,不支持位運算符 需要自己實現
4.5?三目運算符,lua中 也不支持 三目運算
5、條件分支語句
5.1?if 條件 then .....end
--if 條件 then .....end
if a > 5 thenprint("123")
endif (a > 5) thenprint("lalala")
endif a >= 3 and a <= 9 thenprint("a在3到9之間")
end
5.2?雙分支
--雙分支
if a < 5 thenprint("123")
elseprint("321")
end
5.3?多分支
--多分支
if a < 5 thenprint("123")
elseif a == 6 thenprint("6")
elseif a == 7 thenprint("7")
elseif a == 8 thenprint("8")
elseif a == 9 thenprint("9")
elseprint("other")
end
說明
lua中沒有switch語法 需要自己實現
lua不支持三目運算符
6、循環語句
6.1?while語句
while 條件 do ...... end
num = 0
--while 條件 do ...... end
while num < 5 doprint(num)num = num + 1
end
6.2?do while語句
repeat ...... until 條件 (注意:條件是結束條件)
num = 0
--repeat ...... until 條件 (注意:條件是結束條件)
repeatprint(num)num = num + 1
until num > 5 --滿足條件跳出 結束條件
6.3?for語句
for i = 1, 5 do -- 默認遞增 i 會默認+1print(i)
endfor i = 1, 10, 2 do --如果要自定義增量 直接逗號后面寫print(i)
endfor i = 5, 1, -1 do --如果要自定義增量 直接逗號后面寫print(i)
end
7、函數
7.1 函數聲明方式
function 函數名()-- body
enda函數名 = function()-- body
end
7.2?無參數無返回值
function F1()print("F1函數")
end
F1()--有點類似 C#中的 委托和事件
F2 = function()print("F2函數")
end
F2()
7.3?有參數
function F3(a)print("參數:"..tostring(a))
end
F3(1)
F3("123")
F3(true)
--如果傳入的參數 和函數參數個數不匹配
--不會報錯 只會補空nil 或者 丟棄
F3()
F3(1, 2, 3)
7.4?有返回值
多返回值時 在前面申明多個變量來接取即可
如果變量不夠 不影響 只接取對應位置的返回值
如果變量多了 不影響 直接賦值nil
function F4(a)return a, "123", true
end
--多返回值時 在前面申明多個變量來接取即可
--如果變量不夠 不影響 只接取對應位置的返回值
--如果變量多了 不影響 直接賦值nil
temp, temp2, temp3, temp4 = F4("123")
print(temp)
print(temp2)
print(temp3)
print(temp4)
7.5?函數的類型
函數類型 就是 function
--函數類型 就是 function
F5 = function()print("123")
end
print(type(F5))
7.6?函數的重載
lua中 函數不支持重載,默認調用最后一個聲明的函數
--函數名相同 參數類型不同 或者參數個數不同
--lua中 函數不支持重載
--默認調用最后一個聲明的函數
function F6()print("我是個帥哥")
endfunction F6(str)print("我怎么樣:"..tostring(str))
endF6()
7.7?變長參數
function F7( ... )--變長參數使用 用一個表存起來 再用arg = {...}for i=1, #arg doprint(arg[i])end
endF7(1,"123",true,4,5,6)
7.8?函數嵌套
一般閉包情況會使用
function F8()return function()print("123")end
endF9 = F8()
F9()--閉包
function F9(x)--改變傳入參數的生命周期return function(y)return x + yend
endf10 = F9(10)
print(f10(5))
8、復雜數據類型 table
8.1 數組
8.1.1 數組申明
lua中 索引從1開始
a = {1,2,nil,3,4,5,6,7,"123",true,nil}
--lua中 索引從1開始
print(a[0])
print(a[1])
print(a[8])
print(a[9])
print(a[3])
--#是通用的獲取長度的關鍵字
--在打印長度的時候 空被忽略
--如果表中(數組中)某一位變成nil 會影響#獲取的長度
print(#a)
8.1.2?數組的遍歷
for i=1,#a doprint("a["..i.."]:"..tostring(a[i]))
end
8.2?二維數組
8.2.1 二維數組申明
a = {{1,2,3,4},{5,6,7,8 }
}
print(a[1][3])
print(a[2][2])
8.2.2?二維數組的遍歷
for i=1,#a dob = a[i]for j=1,#b doprint("a["..i.."]["..j.."]:"..b[j])end
end
8.3?自定義索引
aa = {[0] = 1,2,3,4, [-1] = 5,6,7}
print(aa[0])
print(aa[-1])
print(aa[1])
print(aa[2])
print(aa[3])
print(aa[4])
print(aa[5])
print(aa[6])
print(#aa)
8.4?字典
8.4.1?字典的申明
a = {["name"] = "小周", ["age"] = 14, ["1"] = 123}
--訪問單個變量 用中括號填鍵 來訪問
print(a["name"])
print(a["age"])
print(a["1"])
--還可以類型 .成員變量 的形式得到值
print(a.name)
print(a.age)
--雖然可以通過 .成員變量的形式得到值 但是不能是數字
print(a["1"])
--修改
a["name"] = "NIBABA"
print(a["name"])
print(a.name)
--新增
a["sex"] = false
str = "name"
print("----------")
print(a[str])
print(a["sex"])
print(a.sex)
--刪除
a["sex"] = nil
print(a.sex)
8.4.2?字典的遍歷
--如果要模擬字典 遍歷一定要用pairs
for k, v in pairs(a) doprint(k, v, 3)
endfor k in pairs(a) doprint(k)print(a[k])
endfor _,v in pairs(a) doprint(v)
end
?8.5?類和結構體
Lua中是默認沒有面向對象的 需要自己實現
Lua中 .和冒號的區別 會默認把調用者 作為第一個參數傳入方法中
Lua中類的表現 更像是一個類中有很多 靜態變量和函數
--Lua中是默認沒有面向對象的 需要自己實現
--成員變量 成員函數。。。
Stundent = {--年齡age = 1,--性別sex = false,--成長函數Up = function()--這樣寫 這個age 和表中的age沒有任何關系 它是一個全局變量--print(age)--想要在表內部函數中 調用表本身的屬性或者方法--一定要指定是誰的 所有 表名.屬性名 或者 表名.方法print(Stundent.age)print("我成長了")end,--學習函數Learn = function(t)print(t.sex)print("好好學習,天天向上")end
}Stundent.Learn(Stundent)
--Lua中 .和冒號的區別 會默認把調用者 作為第一個參數傳入方法中
Stundent:Learn()--申明表后 在表外去申明表有的變量和方法
Stundent.name = "小周"Stundent.Speak = function()print("說話")
end
--函數的第三種申明
function Stundent:Speak2()--lua中 有一個關鍵字 self 表示 默認傳入的第一個參數print(self.name.."說話")
end--C#要是使用類 實例化對象new 靜態直接點
--Lua中類的表現 更像是一個類中有很多 靜態變量和函數
print(Stundent.age)
Stundent.Up()
Stundent.Speak()
Stundent:Speak2()
Stundent.Speak2(Stundent)
8.6?表的公共操作
8.6.1?插入,table.insert()
t1 = {{age = 1, name = "123"}, {age = 2, name = "345"}}t2 = { name = "DLS", sex = false}--插入
print(#t1)
table.insert(t1, t2)
print(#t1)
print(t1[1])
print(t1[2])
print(t1[3])
print(t1[3].name)
?8.6.2?刪除,table.remove()
--刪除指定元素
--remove方法 傳表進去 會移除最后一個索引的內容
table.remove(t1)
print(#t1)
print(t1[1])
print(t1[2])
print(t1[3])--remove方法 傳兩個參數 第一個參數 是要移除內容的表
--第二個參數 是要移除內容的索引
table.remove(t1, 1)
print(#t1)
print(t1[1])
print(t1[2])
print(t1[3])
8.6.3?排序,table.sort()
t2 = {5,2,7,9,5}
--傳入要排序的表 默認 降序排序
table.sort(t2)
for _,v in pairs(t2) doprint(v)
end
8.6.4?降序,table.sort
--傳入兩個參數 第一個參數是用于排序的表
--第二個參數是 排序規則函數
table.sort( t2, function(a, b)if(a > b) thenreturn trueend
end )
for _,v in pairs(t2) doprint(v)
end
?8.6.5?拼接,table.concat
tb = {"123", "456", "789", "10101"}
str = table.concat( tb, ";" )
print(str)
9、迭代器遍歷
迭代器遍歷 主要是用來遍歷表的
#得到長度 其實并不準確 一般不要用#來遍歷表
9.1?ipairs迭代器遍歷
--ipairs
--ipairs遍歷 還是 從1開始往后遍歷的 小于等于0的值得不到
--只能找到連續索引的 鍵 如果中間斷序了 它也無法遍歷后面的內容
for i,k in ipairs(a) doprint("ipairs遍歷鍵值"..i.."_"..k)
end
9.2?ipairs迭代器遍歷
--它能夠把所有的鍵都找到 通過鍵可以得到值
for k,v in pairs(a) doprint("ipairs遍歷鍵值"..k.."_"..v)
endfor k in pairs(a) doprint("pairs遍歷鍵"..k)
end
10、多腳本執行
10.1 全局變量和本地變量
--全局變量
a = 1
b = "1dasd"for i=1,2 doc = "TLS"
endprint(c)
--本地(局部)變量的關鍵字 local
for i=1,2 dolocal d = "TLS"print("循環中的d"..d)
endprint(d)function Fun()local tt = "1131"
end
Fun()print(tt)
local tt2 = "131"
print(tt2)
10.2?多腳本執行
關鍵字require("腳本名")
--關鍵字 require("腳本名") require('腳本名')
require("Test")
print(testA)
print(testLocalA)
10.3?腳本卸載
--如果是require加載執行的腳步 加載一次過后不會再被執行
print(package.loaded["Test"])
require("Test")
--package.loaded["腳本名"]
--返回值是boolean 意思是 該腳本是否被執行
print(package.loaded["Test"])
package.loaded["Test"] = nil
print(package.loaded["Test"])--require 執行一個腳本時 可以在腳本最后返回一個外部希望獲取的內容
local testLocalA = require("Test")
print(testLocalA)
10.4?大G表
--_G表是一個總表(table) 它將我們申明的所有全局的變量都存儲在其中
for k,v in pairs(_G) doprint(k, v)
end
--本地變量 加了local的變量是不會存到大_G表中
11、特殊用法
11.1?多變量賦值
a, b, c = 1, 2, 3
print(a)
print(b)
print(c)
--多變量賦值 如果后面的值不夠 會自動補空
a, b, c = 1, 2
print(a)
print(b)
print(c) --nil
--多變量賦值 如果后面的值多了 會自動省略
a, b, c = 1, 2, 3,4,5
print(a)
print(b)
print(c)
11.2?多返回值
function Test()return 10,20,30,40
end--多返回值 你用幾個變量接 就有幾個值
--如果少了 就少接幾個 如果多了 就自動補空
a,b,c = Test()
print(a)
print(b)
print(c)a,b,c,d,e = Test()
print(a)
print(b)
print(c)
print(d)
print(e) --nil
11.3?and or
邏輯與 邏輯或
and or 他們他們不僅可以連接 boolean 任何東西都可以用來連接
在lua中 只有 nil 和 false 才認為是假
"短路" --對于and來說 有假則假 對于or來說 有真則真
所有 他們只需要判斷 第一個 是否滿足 就會停止計算了
--邏輯與 邏輯或
--and or 他們他們不僅可以連接 boolean 任何東西都可以用來連接
--在lua中 只有 nil 和 false 才認為是假
--"短路" --對于and來說 有假則假 對于or來說 有真則真
--所有 他們只需要判斷 第一個 是否滿足 就會停止計算了
print( 1 and 2)
print( 0 and 1)
print( nil and 1)
print( false and 1)
print( true and 1)print(true or 1)
print(false or 1)
print(nil or 2)
lua不支持三目運算符,使用and or 可以實現三目運算
--lua不支持三目運算符 使用and or 可以實現三目運算
x = 3
y = 2
-- ? :
local res = (x>y) and x or y
print(res)-- (x>y) and x --> x
-- x or y -->x-- (x>y) and x --> (x>y)
-- (x>y) or y --> y
12、協同程序
12.1 協程的創建
--常用方式
--coroutine.create()
fun = function()print(123)
end--方式1
co = coroutine.create(fun)
--協程的本質是一個線程對象
print(co)
print(type(co))--方式2
--coroutine.wrap()
co2 = coroutine.wrap(fun)
print(co2)
print(type(co2))
12.2?協程的運行
--第一種方式 對應的 是通過 create創建的協程
coroutine.resume(co)
--第二種方式
co2()
12.3?協程的掛起
fun2 = function()local i = 1while true doprint(i)i = i + 1--協程的掛起函數print(coroutine.status(co3))print(coroutine.running())coroutine.yield(i)end
endco3 = coroutine.create(fun2)
--默認第一個返回值 是 協程是否啟動成功
--yield里面的返回值
isOk,tempI = coroutine.resume(co3)
print("tempI"..tempI)
isOk,tempI = coroutine.resume(co3)
print(tempI)
isOk,tempI = coroutine.resume(co3)
print(tempI)co4 = coroutine.wrap(fun2)
co4()
co4()
co4()
12.4?協程的狀態
--coroutine.status(協程對象)
--dead 結束
--suspended 暫停
--running 進行中
print(coroutine.status(co3))
print(coroutine.status(co))--這個函數可以得到當前正在 運行的協程的線程號
print(coroutine.running())
13、元表
13.1?元表概念
任何表變量都可以作為另一個表變量的元表
任何表變量都可以有自己的元表(爸爸)
當我們子表中進行一些特定操作時
會執行元表中的內容
13.2?設置元表
meta = {}
myTable = {}
--設置元表函數
--第一個參數 子表
--第二個參數 元表(爸爸)
setmetatable(myTable, meta)
13.3?特定操作
13.3.1?__tostring
當子表要被當做字符串使用時 會默認調用它的元表中的tostring方法
meta2 = {--當子表要被當做字符串使用時 會默認調用這個元表中的tostring方法__tostring = function(t)return t.nameend
}
myTable2 = {name = "TLS123"
}
--設置元表函數
--第一個參數 子表
--第二個參數 元表(爸爸)
setmetatable(myTable2, meta2)print(myTable2)
13.3.2?__call
當子表被當做一個函數來使用時 會默認調用這個__call中的內容
當希望傳參數時,默認第一個參數是調用者自己
meta3 = {--當子表要被當做字符串使用時 會默認調用這個元表中的tostring方法__tostring = function(t)return t.nameend,--當子表被當做一個函數來使用時 會默認調用這個__call中的內容--當希望傳參數是 一定要記住 默認第一個參數 是調用者自己__call = function(self, a)print(self)print(a)print("TLS好帥")end
}
myTable3 = {name = "TLS123"
}
--設置元表函數
--第一個參數 子表
--第二個參數 元表(爸爸)
setmetatable(myTable3, meta3)
--把子表當做函數使用 就會調用元表的 __call
myTable3(1)
13.3.3?運算符重載
運算符+ | __add |
運算符-? | __sub |
運算符* | __mul |
運算符/ | __div |
運算符% | __mod |
運算符^冪運算 | __pow |
運算符== | __eq |
運算符< | __lt |
運算符<= | __le |
運算符.. | __concat |
meta4 = {--相當于運算符重載 當子表使用+運算符時 會調用該方法--運算符+__add = function(t1, t2)return t1.age + t2.ageend,--運算符-__sub = function(t1, t2)return t1.age - t2.ageend,--運算符*__mul = function(t1, t2)return t1.age * t2.ageend,--運算符/__div = function(t1, t2)return t1.age / t2.ageend,--運算符%__mod = function(t1, t2)return t1.age % t2.ageend,--運算符^ 冪運算__pow = function(t1, t2)return t1.age ^ t2.ageend,--運算符==__eq = function(t1, t2)return t1.age == t2.ageend,--運算符<__lt = function(t1, t2)return t1.age < t2.ageend,--運算符<=__le = function(t1, t2)return t1.age <= t2.ageend,--運算符..__concat = function(t1, t2)return t1.age .. t2.ageend
}
myTable4 = {age = 1
}setmetatable(myTable4, meta4)
myTable5 = {age = 2
}
setmetatable(myTable5, meta4)print(myTable4 + myTable5)
print(myTable4 - myTable5)
print(myTable4 * myTable5)
print(myTable4 / myTable5)
print(myTable4 % myTable5)
print(myTable4 ^ myTable5)print(myTable4 == myTable5)
print(myTable4 < myTable5)
print(myTable4 <= myTable5)
print(myTable4 > myTable5)
print(myTable4 >= myTable5)
print(myTable4 .. myTable5)
13.3.4?__index
當子表中 找不到某一個屬性時
會到元表中 __index指定的表去索引
meta6 = {age = 1
}
meta6.__index = meta6
myTable6 = {}
setmetatable(myTable6, meta6)--得到元表的方法
print(getmetatable(myTable6))--__index 當子表中 找不到某一個屬性時
--會到元表中 __index指定的表去索引
print(myTable6.age)
--rawget 當我面使用它時 會去找自己身上有沒有這個變量
--myTable6.age = 4
print("rawget")
print(rawget(myTable6, "age"))
13.3.5 __newindex
__newIndex 當子表賦值時,如果賦值一個不存在的索引
如果元表設置了__newIndex,那么會把這個值賦值到元表的__newindex所指的表中 不會修改自己
--newIndex 當賦值時 如果賦值一個不存在的索引
--那么會把這個值賦值到newindex所指的表中 不會修改自己
meta7 = {}
meta7.__newindex = {age = 1
}
myTable7 = {}
--myTable7.__newindex = {}
setmetatable(myTable7, meta7)
myTable7.age = 14
print(myTable7.age)
print(meta7.__newindex.age)
rawset(myTable7, "age", 123)
print(myTable7.age)
14、面向對象
14.1?封裝
--面向對象 類 其實都是基于 table來實現
--元表相關的知識
Object = {}
Object.id = 1function Object:Test()print("TestFun id: "..self.id)
end--冒號 是會自動將調用這個函數的對象 作為第一個參數傳入的寫法
function Object:new()--self 代表的是 默認傳入的第一個參數--對象就是變量 返回一個新的變量--返回出去的內容 本質上就是表對象local obj = {}--元表知識 __index 當找自己的變量 找不到時 就會去找元表當中__index指向的內容self.__index = selfsetmetatable(obj, self)return obj
endlocal myObj = Object:new()
print(myObj)
print(myObj.id)
myObj:Test()myObj.id = 2
--對空表中 申明一個新的屬性 叫做id
print(myObj.id)
print(Object.id)
myObj:Test()
14.2?繼承
--C# class 類名 : 繼承類
--寫一個用于繼承的方法
function Object:subClass(className)-- _G知識點 是總表 所有申明的全局變量 都以鍵值對的形式存在其中_G[className] = {}--寫相關繼承的規則--用到元表local obj = _G[className]self.__index = self--子類 定義一個base屬性 base屬性代表父類obj.base = selfsetmetatable(obj, self)return obj
endObject:subClass("Person")local p1 = Person:new()
print(p1.id)
p1.id = 100
print(p1.id)
p1:Test()Object:subClass("Monster")
local m1 = Monster:new()
print(m1.id)
m1.id = 10
print(m1.id)
m1:Test()
14.3?多態
--相同行為 不同表現 就是多態
--相同方法 不同執行邏輯 就是多態
Object:subClass("GameObject")
GameObject.posX = 0
GameObject.posY = 0
function GameObject:Move()self.posX = self.posX + 1self.posY = self.posY + 1print("移動后位置pos:("..self.posX..","..self.posY..")")
endGameObject:subClass("Player")
function Player:Move()--base 指的是 GameObject 表(類)--這種方式調用 相對與時把基類 作為第一個參數傳入了方法中--避免把基類表 傳入到方法中 這樣相當于就是公用一張表的屬性了--我們如果要執行父類邏輯 不要直接使用冒號調用--要通過.調用 然后自己傳入第一個參數self.base.Move(self)
endlocal p1 = Player:new()
p1:Move()
p1:Move()
--目前這種寫法 有坑 不同對象使用的成員變量 居然是相同的成員變量
local p2 = Player:new()
p2:Move()
15、基類 Object
15.1 實現萬物之父?所有對象的基類 Object
--面向對象實現
--萬物之父 所有對象的基類 ObjectObject = {}
function Object:new()local obj = {}--給空對象設置元表 以及 __indexself.__index = selfsetmetatable(obj, self)return obj
end
function Object:subClass(className)--根據名字生成一張表 就是一個類_G[className] = {}local obj = _G[className]--設置自己的“父類”obj.base = self--給子類設置元表 以及 __indexself.__index = selfsetmetatable(obj, self)--return obj
end
15.2 使用方法
--申明一個新的類
Object:subClass("GameObject")
--成員變量
GameObject.posX = 0
GameObject.posY = 0
--成員方法
function GameObject:Move()self.posX = self.posX + 1self.posY = self.posY + 1
end--實例化對象使用
local obj = GameObject:new()
print(obj.posX)
obj:Move()
print(obj.posX)