三十分鐘入門 lua

三十分鐘學會 lua

lua是的小巧的腳本語言,它的設計目的是爲了可以嵌入到應用程序中,從而爲應用程序提供靈活的擴展和定製功能。javascript

先執行百度安裝好 lua,本文是採用 vscode 運行的,windows 用戶可使用lua 自帶的編輯器。php

Lua-logo-nolabel

註釋

-- 這是單行註釋
--[[
    這裏是多行註釋
    註釋
--]]

數據類型

ua 是動態類型語言,變量不要類型定義,只須要爲變量賦值。 值能夠存儲在變量中,做爲參數傳遞或結果返回。java

Lua 中有 8 個基本類型分別爲:nil、boolean、number、string、userdata、function、thread 和 table。python

數據類型 描述
nil 這個最簡單,只有值nil屬於該類,表示一個無效值(在條件表達式中至關於false)。
boolean 包含兩個值:false和true。
number 表示雙精度類型的實浮點數
string 字符串由一對雙引號或單引號來表示
function 由 C 或 Lua 編寫的函數
userdata 表示任意存儲在變量中的C數據結構
thread 表示執行的獨立線路,用於執行協同程序
table Lua 中的表(table)實際上是一個"關聯數組"(associative arrays),數組的索引能夠是數字、字符串或表類型。在 Lua 裏,table 的建立是經過"構造表達式"來完成,最簡單構造表達式是{},用來建立一個空表。

運算符

操做符 描述 實例
+ 加法 A + B 輸出結果 30
- 減法 A - B 輸出結果 -10
* 乘法 A * B 輸出結果 200
/ 除法 B / A w輸出結果 2
% 取餘 B % A 輸出結果 0
^ 乘冪 A^2 輸出結果 100
- 負號 -A 輸出結果 -10

語法

基本語法

bool = nil          -- 這個最簡單,只有值nil屬於該類,表示一個無效值(在條件表達式中至關於false)。
id = 1              -- 聲明整數
amount = 1.2        -- 聲明整數(lua 整數和小數都叫作整數)
name = 'jacky'      -- 聲明字符串,單引號雙引號一個意思,都是字符串
nickName = "哈基石"  -- 聲明字符串
local age = 18      -- 聲明局部變量,帶有 local 的是局部定義,不帶有的是全局定義
print(id..name)     -- 鏈接兩個變量或字符相似 php 中的 . 和 javascript 中的 +

Lua if else

主要是先熟悉一下 Lua 的語法結構,你不用記後面會大部分用到,有一點印象便可。golang

bool = true -- 定義全局變量
if bool == true then 
    print(true) -- 輸出 true
end

if 0 then
    print(true) -- 輸出 true
end

if nil then
    print(true)  -- 不輸出 重點記憶
end

if bool == true then
    print(true) -- 輸出 true
else
    print(false)
end

local num = 3
if num == 1 then
    print(1)
elseif num == 2 then
    print(2)
else
    print(3) -- 輸出3
end

table

其實 table 應該放後面學的,但總以爲放後面會致使知識很零散,沒有辦法高效學習。學會了 table,本文基本上60%就已經學完了。sql

相對於其餘語言而言,lua 不須要學習那麼多結構像數組,結構體,map,切片之類的。都說 php 的數組一招鮮走遍天下,啥都能幹。windows

可是 lua更恐怖,有着更強大的功能呢,包括數組,類,匿名...數組

數組

lua 的數字鍵值是從1開始的,這一點須要特別注意。數據結構

一維數組

數字做爲 key 的數組閉包

--建立一個空的 table
tab = {}
-- 直接初始化 table
tab = {"java", "golang", "lua", "python"}
-- 數字下標訪問
print(tab[1])  -- 輸出 java
print(tab[2])  -- 輸出 golangtabl
tab[1] = "C#"  -- 賦值
tab[7] = "C++" -- 賦值
print(tab[1])  -- 輸出 C# 
print(tab[7])  -- 輸出 C++
tab[1] = nil   -- 刪除數組中的元素, key 保留值爲 nil
print(tab[1])  -- 輸出 nil
print(tab[1000]) -- 輸出 nil 不會報錯哦

字符串做爲 key 的數組

tab = {beijing="北京", shanghai="上海", chengdu="成都"}
tab["hangzhou"] = "杭州"
print(tab.beijing, tab.hangzhou, tab["shanghai"]) -- 輸出 北京 杭州 上海

總結: 若是是數字做爲索引,那麼須要用[]來訪問,若是字符串做爲索引,那麼可使用[], 和 xx.xxx兩種方式均可以訪問和修改

table的增長

-- 新增元素到 tab 的末尾
tab = {"beijing", "shanghai"}
table.insert(tab, "hangzhou") -- 將廣州寫入tab的末尾,下標就是3
print(tab[3]) -- hangzhou

-- 新增到指定的位置
table.insert(tab, 1, "neimeng") -- 插入到1的位置,其原來位置後面的元素向後偏移
print(tab[1], tab[2]) -- 輸出 neimeng beijing

table 的刪除

tab = {"java", "C++", "golang", "sql"}
res = table.remove(tab, 2) -- 刪除第二個元素,C++,其餘元素會進行補位(向前偏移)
print(res, tab[1], tab[2]) -- 輸出C++     java    golang

多維數組

多維 table 與一位多了一層,使用狀況徹底同樣。

tab2 = {{}} -- 定義個空的二維 tab

tab2 = {{"北京", "上海"}, {"java", "go"}}
print(tab2[1][1], tab2[2][2]) -- 輸出 北京 go

元表 matatable

元表( metatable)是一個表,它是使用鍵集和相關元方法來修改附加到的表的行爲。這些元方法是強大的Lua功能。

  • __index 這是 metatable 最經常使用的鍵。

    當你經過鍵來訪問 table 的時候,若是這個鍵沒有值,那麼Lua就會尋找該table的metatable,是否存在__index 方法。若是存在就會調用它,不存在就會返回 nil

  • __newindex 若是對 table 裏面的數據進行新增,例如 table["xxx"] = 300 那麼就會調用 metatable __newindex方法
  • __call 若是對 table 直接調用,那麼會調用 metatable 中的 __call這個方法, 例如調用tab()
  • __tostring 若是堆 table 直接輸出,那麼會調用 metatable 中的__tostring 這個方法,例如print(tab)
-- __index 索引
tab = {10, 20, 30}
tab2 = {} -- __newindex 賦值方式1
metatab = {
    -- __index 若是tab中不存在key,則調用__index。
    __index = function(t, k) 
        print(string.format( "調用了 tab 不存在的索引,key=%s", k))
    end,
    -- __newindex = tab2, -- 賦值方式1,直接賦值給 tab2 例如調用 xxx["user"]=1 ,那麼tab2["user"]的值爲1
    __newindex = function(t, k, v) -- 賦值方式2方法自定義調用
        rawset(t, k, v) -- 賦值給 t
        print(string.format( "新增了tab不存在的索引,k=%s, v=%s", k, v))
    end,
    __call = function(t, arg1, arg2)
        print(string.format("調用了__call, arg1=%s, arg2=%s,返回了true", arg1, arg2))
    end,
    __tostring = function(t) 
        print("調用了直接輸出 __tostring") -- 直接輸出 tab 會調用這個方法
        return "call __tostring"
    end,
    __le = function(t, newtab) --兩個表調用了 <= 比較運算符
        print("調用了兩個表==運算符")
        return true
    end,
    __add = function(t, newtab) -- 根據本身的場景來處理,這裏處理的是兩個表合併
        print("調用了__add")
        for k, v in pairs(newtab) do -- 尚未學習 for,先不要關心
            table.insert(t, v)
        end
        return t
    end,
}

-- 對指定 table 設置元表(metatable)
restab = setmetatable(tab, metatab) 
restab[20] = 2000 -- 調用 __index 方法
restab(32, 45)    -- 調用 __call 方法
print(restab)     -- 調用 __tostring

newtab = {80, 90}
res = restab + newtab -- 調用兩個表想加
if restab <= n then   -- 調用了 __le
-- do something
end

操做運算符

模式 描述
__add 對應的運算符 '+'.
__sub 對應的運算符 '-'.
__mul 對應的運算符 '*'.
__div 對應的運算符 '/'.
__mod 對應的運算符 '%'.
__unm 對應的運算符 '-'.
__concat 對應的運算符 '..'.
__eq 對應的運算符 '=='.
__lt 對應的運算符 '<'.
__le 對應的運算符 '<='.

好吧,原表終於學完了,若是你在學習中也進行實際操做,那麼必定超過30分鐘了。不過堅持一下,剩下的部分很快了。有了元表的基礎就能夠學習面向對象了

Lua 循環

Lua 的循環有3中分別是 for, while, repeat unitl。其中 for 包括基本 for 與泛型 for,至關於其餘語言的 for in 或者 foreach。

while 循環

-- 最簡單的循環
a = 5
while a >= 0 do
    print(a) -- 輸出 5 4 3 2 1 0
    a = a -1
end

for 循環

數值循環

for 循環分爲兩種,數值型和泛型,數值型比其餘語言更簡介,也有點怪怪的,熟悉就好。

數值型的 for 循環長這樣

for var=exp1,exp2,exp3 do  
    <執行體>  
end

exp1表明初始化的數值,exp2表明結束條件,注意這裏沒有比較運算符,exp3表明步長,也能夠省略。

for i = 1, 5, 1 do 
    print(i) -- 輸出 1 2 3 4 5
end

-- 步長是2的狀況
for i = 1, 5, 2 do 
    print(i) -- 輸出 1 3 5
end

步長也就是 exp3能夠省略,默認步長是1

for i = 1, 5 do 
    print(i) -- 輸出 1 2 3 4 5
end

這裏須要注意一點,與其餘語言不同 for的三個表達式在循環開始前一次性求值,之後再也不進行求值。好比上面的f(x)只會在循環開始前執行一次,其結果用在後面的循環中。

泛型循環

泛型循環有兩個迭代函數 pairs 與 ipairs,他們的區別是 ipairs遇到nil會中止,pairs會輸出nil值而後繼續下去,文字看不動不要緊,看代碼。

table = {"1", "2", "3", nil, "5"}
for k, v in pairs(table) do
    print("k="..k..",val="..v)
end

這個栗子會輸出

k=1,val=1
k=2,val=2
k=3,val=3
k=5,val=5
-- ipairs 若是文字沒有理解啥意思,能夠對比一下上一個栗子與這個栗子的結果
table = {"1", "2", "3", nil, "5"}
for k, v in ipairs(table) do
    print("k="..k..",val="..v)
end

這個栗子會輸出

k=1,val=1
k=2,val=2
k=3,val=3

repeat until

-- repeat
a = 1 
repeat  -- 開始重複
    print(a)
    a = a +1
until(a>3) -- 條件 直到條件判斷語句(condition)爲 true 纔會中止執行。

這個栗子會輸出

1
2
3

迭代器

趁熱打鐵,迭代器與 for 循環一塊兒結合着理解會很好理解。其實上個例子中 pairs 與 ipairs 就是兩個泛型迭代器,lua 內部都給咱們實現好了。

迭代器(iterator)是一種對象,它可以用來遍歷標準模板庫容器中的部分或所有元素,每一個迭代器對象表明容器中的肯定的地址。

在 Lua 中迭代器是一種支持指針類型的結構,它能夠遍歷集合的每個元素。

泛型迭代器

泛型 for 在本身內部保存迭代函數,實際上它保存三個值:迭代函數、狀態常量、控制變量。

無狀態的迭代器

無狀態的迭代器是指不保留任何狀態的迭代器,所以在循環中咱們能夠利用無狀態迭代器避免建立閉包花費額外的代價。

-- 迭代函數 state 只有在初始化的時候賦值
function square(max, add) 
    if add >= max then -- 當累加器到達最大返回 nil 外部會跳出循環
        return nil
    else 
        add = add+1 -- lua 沒有 ++
        return add, add*add -- 返回兩個參數與 go 類似,返回當前的值和乘
    end
end

for i, j in square , 5, 0 do -- 調用自定義迭代器 
    print(i, j)
end

這個栗子輸出

1       1
2       4
3       9
4       16
5       25
6       36
7       49
8       64
9       81

多狀態迭代器

不少狀況下,迭代器須要保存多個狀態信息而不是簡單的狀態常量和控制變量,最簡單的方法是使用閉包,還有一種方法就是將全部的狀態信息封裝到 table 內,將 table 做爲迭代器的狀態常量,由於這種狀況下能夠將全部的信息存放在 table 內,因此迭代函數一般不須要第二個參數

-- 多狀態迭代器
tab = {"google", "baidu"}
function square (con)
    local index = 0
    local count = #con -- #表明計算長度

    return function() -- 這是一個匿名函數會直接調用
        index = index + 1
        if index <= count then -- index 小於總長度
            return con[index] -- 返回這個 val
        end
    end
end

for val in square(tab) do
    print(val) -- 輸出 google baidu
end

函數

支持返回多個返回值

function op(key, val) 
    return key, val -- 支持兩個參數返回
end
arg1, arg2 = op("user", 100)

參數支持傳遞函數

-- 參數函數傳遞的方式
function  sum(a, b, func) 
    return func(a, b)
end

function func(a, b) 
    return a + b
end

val = sum(10, 20, func)
print(val) -- 輸出30

匿名函數的方式傳遞

function max(a, b, func)
    max = func(a, b)
    print(max) -- 輸出 39
end

getmax = function(a, b) 
    if a > b then
        return a
    else 
        return b
    end
end
max(10, 39, getmax)

可變參數

function args(...) 
    local arg = {...} -- 局部定義不然會有重複賦值
    print("總共傳入 " .. select("#",...) .. " 個數")
    print(arg[1], arg[2], arg[3])
end
args(10, 20, 30)

這個栗子會輸出

總共傳入 3 個數
10      20      30

面向對象

基礎定義

.的定義定義方式,不能直接使用 self

-- table 引用類型
phone = {
    name   = "馬化騰",
    memory = "128GB"
}

phone.call = function(self) 
    str = string.format( "%s 正在打電話", self.name)
    print(str)
end

phone.call(phone) -- 輸出 馬化騰 正在打電話

:的定義方式

phone = {
    name  = "馬化騰",
    pname = "李彥宏"
}

function phone:call() 
    str = string.format( "%s 正在打電話", self.name)
    print(str)
end

function phone:say(name) 
    self.pname = name
    str = string.format( "%s 說%s你趕忙充錢", self.name, self.pname)
    print(str)
end
phone:call()
phone:say("馬雲")

輸出

馬化騰 正在打電話
馬化騰 說馬雲你趕忙充錢

完整的面向對象實例

-- table 引用類型
phone = {
    name  = "馬化騰",
}

function phone:call() 
    str = string.format("%s 正在打電話", self.name)
    print(str)
end

function phone:new(sel)
    sel = sel or {}
      -- 因爲 table 是引用類型,這裏須要從新賦值
    setmetatable(sel, {__index = self}) -- 將 self 賦給 sel 
    return sel
end

mahuat = phone:new()
mayun = phone:new()
mahuat.name = "馬化騰"
mayun.name  = "馬雲"
mahuat:call() -- 注意 :call()的形式,不然沒法得到到 self
mayun:call()

輸出

馬化騰 正在打電話
馬雲 正在打電話

Lua 繼承

看代碼,認真看,沒那麼繁瑣

Phone = {
   name  = "",
}

function Phone:call() -- 定義基本方法
   str = string.format("%s 正在打電話", self.name)
   print(str)
end

function Phone:new(sel)
   sel = sel or {}
   setmetatable(sel, {__index = self}) -- 將 self 賦給 sel
   return sel
end

-- Mahuat繼承了 Phone 方法
Mahuat = Phone:new()
function Mahuat:say() 
   self.name = "馬化騰"
   self:call() -- 調用父類的方法
   str = string.format("%s 說趕忙充錢!", self.name)
   print(str)
end
function Mahuat:new(sel)
   sel = sel or Phone:new()
   setmetatable(sel, self)
   self.__index = self
   return sel 
end
Mahuat:say() -- 調用本身的方法

-- Mayun繼承了 Phone 方法
Mayun = Phone:new()
function Mayun:say() 
   self.name = "馬雲"
   self:call() -- 調用父類的方法
   str = string.format("%s 說快還花唄!", self.name)
   print(str)
end
function Mayun:new(sel)
   sel = sel or Phone:new()
   setmetatable(sel, self)
   self.__index = self
   return sel 
end
Mayun:say() -- 調用本身的方法

-- 派生重寫
liyanhong = Phone:new()
function liyanhong:call() 
   print("咱們不生產假藥!咱們只是假藥的搬運工~ ")
end
-- 重寫了 call 方法
function liyanhong:say() 
   self.name = "李彥宏"
   self:call() -- 調用父類的方法
   str = string.format("%說歐耶!", self.name)
   print(str)
end
function liyanhong:new(sel)
   sel = sel or Phone:new()
   setmetatable(sel, self)
   self.__index = self
   return sel 
end
liyanhong:say() -- 調用本身的方法

這個例子輸出

馬化騰 正在打電話
馬化騰 說趕忙充錢!
馬雲 正在打電話
馬雲 說快還花唄!
咱們不生產假藥!咱們只是假藥的搬運工~
李彥宏 說歐耶!

恭喜您讀到這裏,實際上尚未完!抱歉了,😄

Lua 的最基礎部分就學完了,還須要一個篇寫其餘的操做,例如文本操做,函數庫調用。

相關文章
相關標籤/搜索