保留字
and break do else elseif
end false for function if
in local nil not or
repeat return then true until while
底線後面大寫的變數(像是:_VERSION)為lua的內部全域變數
符號
單行註解使用( -- ) 多行註解使用( --[[ .. ]] )
運算符號
- == 相等表示兩個變數引用的是同一個數據
- ~=
- >
- <
- > =
- < =
邏輯符號
and or not
-- a ? b : c
a and b or c
優先順序
- ^
- not - (unary)
- /
- -
- ..
- < 、 > 、 < = 、 >= 、 ~= 、 ==
- and
- or
其他運算符號
- .. 連接兩字串
- # 取字串長度或表的長度
變數
Lua 定義變數沒有指定類型
Lua中有八種基本類型: nil,boolean,number, string,function,userdata, thread和table
nil : 表示無效值(條件式為false),無須宣告,直接使用變數即為nil若本有定義的變數被設為nil,等同於清空,
number : double,數字寫法都被視為number
userdata : struct
thread : coroutine,可將一個函數分幾部分運行
table : 關連數組,空表可用{},數組可以是數字或字串,array、map
給值
local 為區域變數,其餘為全域變數 x,y=1,2,3 => x=1,y=2 x,y=1 => x=1,y=nil 做swap的動作,只需要 x,y = y,x
String
字串用'..'或"..",可使用跳脫字元
多行可使用 [[..]] or [=[..]=] or [==[..]==] ...
字串操作
- string.upper(argument) 和 string.lower(argument)
- string.gsub(mainString,findString,replaceString,num) num為次數
- string.find (str, substr, [init, [end]]) 返回值為找到位置的頭尾,不存在則返回nil
- string.reverse(arg)
- string.format(...)
- string.char(arg) 和 string.byte(arg[,int])
- string.len(arg)
- string.rep(string, n)) 重複n次
lua遇到數字print時會自動轉換類型
所以若要輸出字串形式,利用字串連接符號(..)須加上空格以防又自動轉換
print(10 .. 20)
function
函數可接受可變數目的參數用(...) return只能放在end前或else前或until前(敘述的結束)
function foo (...)
return --<< SYNTAX ERROR
...
do return end -- OK
...
end
function foo (...)
local ary={...}
...
end
當你不想要某個參數時,可以用_代替掉
local _ , x = string.find(s, p)
疊代函數
類似機器輸送帶,一次輸出一包 內部保存的疊代函數,包含疊代函數、狀態常數、控制變數 以lua的ipairs為例 疊代函數iter、狀態常數a、控制變數初始值0;然後Lua調用iter(a,0)返回1,a[1](除非a[1]=nil);第二次调用iter(a,1)返回2,a[2]……直到第一個nil元素
function iter (a, i)
local _i = i and i + 1 or 1
local v = a[_i]
if v then
return _i, v
end
end
function ipairs (a)
return iter, a, 0
end
loop
有break可使用
while
while( true )
do
print("1")
end
for
var從exp1變化到exp2,每次變化以exp3為遞增var,並執行一次。exp3是可選的,如果不指定,默认为1。
for var=exp1,exp2,exp3 do
...
end
in 後面的表達式可能為內部保存的疊代函數,包含疊代函數、狀態常數(table)、控制變數 類似foreach
for i,v in ipairs(a)
do print(v)
end
rpeat until
類似do ..while
i = 10
repeat
print(i)
i = i -1
until(i < 0)
table
一般table所引從1為起始,也可以從0或負數開始
array = {}
for i= -2, 2 do
array[i] = i *2
print(array[i])
end
ipairs 讀取table的i數值只能為+1遞增,遇到nil停止
pairs 讀取table的數值直到結束
stars = {[1] = "Sun", [5] = 'Earth',[2] = "Moon",[4] = "Zoo"}
ipairs結果:
1 Sun
2 Moon
pairs結果:都會跑到但[key]-[value]形式的表是隨機的,跟hash有關
4 Zoo
1 Sun
2 Moon
5 Earth
最好的方式是:
stars = {"Sun", "Moon", “Earth”, "Zoo"}
1 Sun
2 Moon
3 Earth
4 Zoo
如果table a 宣告後並設至元素再將b設為a,那麼a與b則指向同一個內存,類似別名,若將a設為nil,則b仍可訪問table的元素,nil可以視為去除別名
a={1,2,3,64}
b=a
a[1]=123
print(a[1].." "..b[1]) --123 123
a=nil
print(a[1]) --error
print(b[1]) -- 123
- table.concat (table [, sep [, start [, end]]]): 元素间以指定的分隔符(sep)隔开
- table.insert (table, [pos,] value):
- table.remove (table [, pos]) 默認為最後一個元素
- table.sort (table [, comp])
Metatable
setmetatable(table,metatable):對指定table設置元表(metatable) getmetatable(table): 返回對象的元表(metatable)。
- metatable 也是個普通的 table
- 每個 table 內都有一些特殊的 key (如 __index, __add…etc)
- 這些特殊 key 不影響 table 本身,而是影響將其當為 metatable 的 table
Lua查找一个表元素时的規則,如下3個步骤:
1.在表中查找,如果找到,返回该元素,找不到则繼續
2.判断該表是否有元表(metatable),如果没有元表,返回nil,有元表则繼續。
3.判断元表(metatable)有没有index方法,如果index方法为nil,则返回nil;如果 index方法是一个表,则重复1、2、3;如果index方法是一个函数,Lua就会调用那个function(table,key),且取得返回值。
Metamethod
- __index為找尋表中的值,欲找尋的值不在表裡則看__index
- __newindex為表的更新,欲更新的值不在表裡則看__newindex
- __call 可用來call function
- __tostring 修改表輸出
- 運算子
-- __add(a, b) for a + b -- __sub(a, b) for a - b -- __mul(a, b) for a * b -- __div(a, b) for a / b -- __mod(a, b) for a % b -- __pow(a, b) for a ^ b -- __unm(a) for -a -- __concat(a, b) for a .. b -- __len(a) for #a -- __eq(a, b) for a == b -- __lt(a, b) for a < b -- __le(a, b) for a <= b
__index:
if __index 為一個table則從該table找尋該值 if __index 為一個function則調用該function (t,k),其返回值會當作找到的結果
__newindex:
if __newindex 為一個table則將要賦予的值給該table if __newindex 為一個function則調用該function (t,k,v)
mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })
print(mytable.key1)
mytable.newkey = "新值2"
print(mytable.newkey,mymetatable.newkey)
mytable.key1 = "新值1"
print(mytable.key1,mymetatable.key1)
執行結果:
value1
nil 新值2
新值1 nil
rawset
使用rawset 函数来更新表,避免死循環;使用rawget 函数跳過__index
mytable = setmetatable({key1 = "value1"}, {
__newindex = function(mytable, key, value)
--mytable.key=value
rawset(mytable, key, "\""..value.."\"")
end
})
mytable.key1 = "new value"
mytable.key2 = 4
print(mytable.key1,mytable.key2) --new value "4"
執行結果:
####\_\_call
t= setmetatable({}, { __call = function(t, a, b, c, whatever) return (a + b + c) * whatever end })
t(1, 2, 3, 4) –- 24
####\_\_tostring:將表轉為string
t = setmetatable({ 1, 2, 3 }, { _tostring = function(t) sum = 0 for , v in pairs(t) do sum = sum + v end return "Sum: " .. sum end })
print(t) -- "Sum: 6"
## module
module相當於函式庫,為一個table,文件最後return module
在其他檔案中使用require\("module"\)
對於自定義的module,,函数 require 有它自己的文件路径加載策略,他會嘗試從 Lua 文件或 C 程式庫中加載module。
require 用于搜索 Lua 文件的路径是存放在全域變數 package.path 中,當 Lua 啟動後,會以環境變數 LUA\_PATH 的值来初始这個環境變數。如果没有找到,则使用一個編譯時定義的默認路徑來初始化。
文件路径以 ";" 号分隔,最后的 2 个 ";;"
####loadlib函數加載的指定函式庫,不先打開,只是返回初始化函數作為Lua的一個函數
local path = "/usr/local/lua/lib/libluasocket.so"
-- 或者 path = "C:\windows\luasocket.dll",这是 Window 平台下
local f = assert\(loadlib\(path, "luaopen\_socket"\)\)
f\(\) -- 真正打开库
## 協同程序(coroutine)
* coroutine.create(函數) : 創建coroutine
,返回為 thread,與resume配合可喚醒函數調用
* coroutine.resume() : 重啟coroutine,return true or false and err
* coroutine.yield() : 掛起coroutine,相當於先停止等待resume,狀態為suspend
,重新啟動
* coroutine.isyieldable () : return true;A running coroutine is yieldable if it is not the main thread and it is not inside a non-yieldable C function.
* coroutine.status():dead:finish,suspend:yield,running:in coroutine function,normal:in another coroutine
* coroutine.wrap() : 創建coroutine,返回一個函數,當調用該函數則重啟coroutine
* coroutine.running() : Returns the running coroutine plus a boolean, true when the running coroutine is the main one
####create 與 wrap 差別
co = coroutine.create( function(i) print(i); end ) coroutine.resume(co, 1)
```
co = coroutine.wrap(
function(i)
print(i);
end
)
co(1)
yield
co2 = coroutine.create(
function()
for i=1,10 do
print(i)
if i == 3 then
print(coroutine.status(co2)) --running
print(coroutine.running()) --thread:XXXXXX not in main >> false
end
coroutine.yield()
end
end
)
coroutine.resume(co2) --1
coroutine.resume(co2) --2
coroutine.resume(co2) --3
print(coroutine.status(co2)) -- suspended
print(coroutine.running()) -- in main >> true
1
2
3
running
thread: 0x7fb801c05868 false
suspended
thread: 0x7fb801c04c88 true
文件 I/O
file = io.open (filename [, mode])
mode 的值有:
模式 描述
r 以只读方式打开文件,该文件必须存在。
w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
r+ 以可读写方式打开文件,该文件必须存在。
w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
a+ 与a类似,但此文件可读可写
b 二进制模式,如果文件是二进制文件,可以加上b
\* 号表示对文件既可以读也可以写
io.open : 打開文件 io.close : 關閉文件 io.input(file) : 默認輸入文件 io.output(file) : 默認輸出文件 io.read() : 讀取文件第一行 io.write("") : 寫入到文件最後一行
io.read()可用參數
- 读取一个数字并返回它。例:file.read("*n")
- 从当前位置读取整个文件。例:file.read("*a")
- (默认)读取下一行,在文件尾 (EOF) 处返回 nil。例:file.read("*l")
- 返回指定字元個數的字串,或在 EOF 时返回 nil。例:file.read(5)
其他io方法:
io.tmpfile():返回一个临时文件句柄,该文件以更新模式打开,程序结束时自动删除
io.type(file): 检测obj是否一个可用的文件句柄
io.flush(): 向文件写入缓冲中的所有数据
io.lines(optional file name): 返回一个迭代函数,每次调用将获得文件中的一行内容,当到文件尾时,将返回nil,但不关闭文件
若需同時處理多個文件可使用file:funciton來代替io.function,則不需指定io.input(file)、io.output(file)
錯誤訊息
assert(type(a) == "number", "a 不是一个数字")
第一個參數為判斷,若為true則才將第二個參數作為錯誤訊息輸出
error (message [, level])
功能:终止正在执行的函数,將引用的function return message作为错误信息(error函数本身永远都不会返回)
通常情况下,error会附加一些错误位置的信息到message头部。
Level:
Level=1[默认]:調用error函数位置(文件+行号)
Level=2:调用error函数的函数位置 (文件+行号)
Level=0:不添加错误位置信息
1.function foo (str)
2. if type(str) ~= "string" then
3. error("string expected1",1)
4. end
5. end
6.foo({x=1})
Level 1: lua: err.lua:3: string expected1
Leve 2: lua: err.lua:6: string expected1
Leve 0: lua: string expected1
pcall(myfunction,[parameter]) return status, errorinfo,沒有錯誤status=true,有錯誤status=false
function myfunction (n)
if type(n) ~= "string" then
error("string expected2")
end
end
status,errorinfo=pcall(myfunction,5)
if status then
print(tostring(errorinfo).." Success")
else
print(tostring(errorinfo).." Failure")
end
xpcall(myfunction,myerrorhandler): 沒有錯誤status=true,有錯誤status=false
function myfunction ()
n = n/nil
end
function myerrorhandler( err )
print( "ERROR:", err )
end
status = xpcall( myfunction, myerrorhandler )
print( status)
實現物件導向(table+function)
冒號的用法,是隱藏了一個運算function,他會將物件本身self給傳遞進去,這樣一來,即使你的物件不叫做Shape 也可以做這些方法喔 metamethod __index是以Shape 本身作為未來查詢索引根據 self=Shape 與真正的物件有點不同,只是共用這個物件,並非獨立擁有自己的物件
Shape = {area = 0}
-- new >> constructor
function Shape:new (o,side)
o = o or {} -- 如果沒有輸入任何資料,則建立一個空table
setmetatable(o, self) -- 設定Object物件的metatable是Shape (Self = Shape )
self.__index = self -- Shape 的metatable是他自己
-- setmetatable(o, {__index = self})
side = side or 0
self.area = side*side;
return o
end
-- printArea >> method
function Shape:printArea ()
print("面积为 ",self.area)
end
h=Shape:new(h,5) -- 將h設定Shape作為他的metatable
h:printArea() -- Shape:printArea()
繼承方式
metamethod __index是以Shape 本身作為未來查詢索引根據
Shape = {area = 0}
-- new
function Shape:new (o,side)
o = o or {}
setmetatable(o, self)
self.__index = self
side = side or 0
self.area = side*side;
return o
end
function Shape:printArea ()
print("面積為 ",self.area)
end
Square = Shape:new()
function Square:new (o,side)
o = o or Shape:new(o,side)
setmetatable(o, self)
self.__index = self
return o
end
--Override
function Square:printArea ()
print("正方形面積 ",self.area)
end