保留字

 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

  1. __index為找尋表中的值,欲找尋的值不在表裡則看__index
  2. __newindex為表的更新,欲更新的值不在表裡則看__newindex
  3. __call 可用來call function
  4. __tostring 修改表輸出
  5. 運算子
    -- __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

results matching ""

    No results matching ""