Lua 是什么?
Lua 是一種輕量小巧的腳本語言,用標准C語言編寫並以源代碼形式開放, 其設計目的是為了嵌入應用程序中,從而為應用程序提供靈活的擴展和定制功能。
Lua 是巴西里約熱內盧天主教大學(Pontifical Catholic University of Rio de Janeiro)里的一個研究小組,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo所組成並於1993年開發。
設計目的
其設計目的是為了嵌入應用程序中,從而為應用程序提供靈活的擴展和定制功能。
Lua 特性
- 輕量級: 它用標准C語言編寫並以源代碼形式開放,編譯后僅僅一百余K,可以很方便的嵌入別的程序里。
- 可擴展: Lua提供了非常易於使用的擴展接口和機制:由宿主語言(通常是C或C++)提供這些功能,Lua可以使用它們,就像是本來就內置的功能一樣。
- 其它特性:
- 支持面向過程(procedure-oriented)編程和函數式編程(functional programming);
- 自動內存管理;只提供了一種通用類型的表(table),用它可以實現數組,哈希表,集合,對象;
- 語言內置模式匹配;閉包(closure);函數也可以看做一個值;提供多線程(協同進程,並非操作系統所支持的線程)支持;
- 通過閉包和table可以很方便地支持面向對象編程所需要的一些關鍵機制,比如數據抽象,虛函數,繼承和重載等。
Lua 基本語法
Lua 學習起來非常簡單,我們可以創建第一個 Lua 程序!
交互式編程:
Lua 提供了交互式編程模式。我們可以在命令行中輸入程序並立即查看效果。
Lua 交互式編程模式可以通過命令 lua -i 或 lua 來啟用:
$ lua -i
$ Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
>
在命令行中,輸入以下命令:
> print("my name is jack lee")
接着我們按下回車鍵,輸出結果如下:
> print("my name is jack lee")
my name is jack lee
腳本式編程:
我們可以將 Lua 程序代碼編寫到一個以 lua 結尾的文件,並執行,該模式稱為腳本式編程,如我們將如下代碼存儲在名為 name.lua 的腳本文件中,並且將腳本放在D:盤
print("my name is jack!")
print("welcome learn lua follow teacher li!")
使用 lua 名執行以上腳本,輸出打印結果
lua d:\Lua\name.lua
注釋
單行注釋
兩個減號是單行注釋:
--
多行注釋
--[[
多行注釋
多行注釋
--]]
變量,函數命名規范
標示符表示一個變量,函數或其他定義項,命名規范以一個字母 A 到 Z 或 a 到 z 或下划線 _后加上字母,下划線 _數字(0到9)。建議不要使用下划線加大寫字母的標示符,因為Lua的保留字也是這樣的。
一般約定,以下划線開頭連接一串大寫字母的名字(比如 _VERSION)被保留用於 Lua 內部全局變量。
Lua 不允許使用特殊字符如 @, $, 和 % 來定義成員名。 Lua 是一個區分大小寫的編程語言。因此在 Lua 中 Run 與 run 是兩個不同的標示符。以下列出了一些正確的標示符:
mohd zara abc move_name a_123
myname50 _temp j a23b9 retVal
關鍵詞
以下列出了 Lua 的保留關鍵字。保留關鍵字不能作為常量或變量或其他用戶自定義標示符:注:(以下關鍵字后續會詳細講解)
| and |
break |
do |
else |
| elseif |
end |
false |
for |
| function |
if |
in |
local |
| nil |
not |
or |
repeat |
| return |
then |
true |
until |
| while |
|
|
|
全局變量
在默認情況下,變量總是認為是全局的。
全局變量不需要聲明,給一個變量賦值后即創建了這個全局變量,訪問一個沒有初始化的全局變量也不會出錯,只不過得到的結果是:nil。
> print(b)
nil
> b=10
> print(b)
10
>
你可以設置全局變量為空,只需要將變量賦值為nil。
b = nil
print(b) --> nil
這樣變量b就好像從沒被使用過一樣。換句話說, 當且僅當一個變量不等於nil時,這個變量即存在。
Lua 數據類型
Lua是動態類型語言,變量不要類型定義,只需要為變量賦值。 值可以存儲在變量中,作為參數傳遞或結果返回。
Lua中有8個基本類型分別為:nil、boolean、number、string、userdata、function、thread和table。 (注:以下數據類型后續做詳細講解)
| 數據類型 |
描述 |
| nil |
表示一個無效值(在條件表達式中相當於false)。 |
| boolean |
包含兩個值:false和true。 |
| number |
表示雙精度類型的實浮點數 |
| string |
字符串由一對雙引號或單引號來表示 "" '' |
| function |
函數 |
| userdata |
表示任意存儲在變量中的C數據結構 |
| thread |
表示執行的獨立線程,用於執行協同程序 |
| table |
Lua 中的表(table)其實是一個"關聯數組",數組的索引可以是數字或者是字符串。在 Lua 里,table 的創建是通過"構造表達式"來完成,最簡單構造表達式是{},用來創建一個空表。 |
我們可以使用type函數測試給定變量或者值的類型:
在sublime編輯器中寫下以下代碼, 按Ctrl+B 編譯。
_str="I am str"
_number=10.116
_bo=false
print(type(str))
print(type(_number))
print(type(_bo))
數據類型具體分析:
nil(空)
nil 類型表示一種沒有任何有效值,它只有一個值 -- nil,例如打印一個沒有賦值的變量,便會輸出一個 nil 值:
> print(type(a))
nil
boolean(布爾)
boolean 類型只有兩個可選值:true(真) 和 false(假),Lua 把 false 和 nil 看作是"假",其他的都為"真"
number(數字)
Lua 默認只有一種 number 類型 -- double(雙精度)類型,以下幾種寫法都被看作是 number
print(type(2))
print(type(2.2))
print(type(0.2))
string(字符串)字符串由一對雙引號或單引號來表示。
string1 = "this is string1"
string2 = 'this is string2'
也可以用 2 個方括號 "[ [ ] ]" 來表示"一塊"字符串。
_str2=[[my name is jack!]]
print(_str2)
在對一個數字字符串上進行算術操作時,Lua 會嘗試將這個數字字符串轉成一個數字:
print("1"+5) --6
print("1"+"6") --7
print("3+7") -- "3+7"
關於字符串拼接,使用.. 對字符串進行拼接
value=11
print("value="..value) --value=11
使用 # (井號)來計算字符串的長度,放在字符串前面,如下實例:
mail = "ukraine_lee@163.com"
print(#mail)
--19
Table(表)
在 Lua 里,table 的創建是通過"構造表達式"來完成,最簡單構造表達式是大括號{},用來創建一個空表。也可以在表里添加一些數據,直接初始化表:
-- 創建一個空的 table
local tbl1 = {}
-- 直接初始表
local tbl2 = {"apple", "pear", "orange", "grape"} --蘋果,梨,橙子,葡萄
local tbl2={X=3,y=4} --指定鍵值初始化 X,Y是鍵,值是3,4
Lua 中的表(table)其實是一個"關聯數組",數組的索引可以是數字或者是字符串。(類似字典)
_table_1={}
_table_1["str_key1"]="str_value"
_table_1["str_key2"]=2
nub_key1=1
_table_1[nub_key1]="value1"
nub_key2=2
_table_1[nub_key2]=13
_table_1[nub_key2]=_table_1[nub_key2]+1
for k,v in pairs(_table_1) do
print(k.."===="..v)
end
不同於其他語言的數組把 0 作為數組的初始索引,在 Lua 里表的默認初始索引一般以 1 開始。
local tbl = {"apple", "pear", "orange", "grape"}
for key, val in pairs(tbl) do
print("Key", key)
end
-- 1 2 3 4
table 不會固定長度大小,有新數據添加時 table 長度會自動增長,沒初始的 table 都是 nil。
_table = {}
for i = 1, 10 do
_table[i] = i
end
-- for k,v in pairs(_table) do
-- print(k,v)
-- end
_table["key"] = "val"
print(_table["key"])
print(_table["none"])
for k,v in pairs(_table) do
print(k,v)
end
表函數的定義和使用:
tab={x=2,y=3}
function tab:setValue(m_x,m_y) --注意定義的時候使用了:冒號
tab.x=m_x
tab.y=m_y
end
tab:setValue(5,6) --注意,在調用的時候也必須和定義時一致使用冒號。
print(tab.x,tab.y)
function(函數)
函數的基本語法:
function function_name(n_value)
return n_value+1
end
print(function_name(7))
函數還可以像下面這樣存在一個變量里:
function function_name(n_value)
return n_value+1
end
print(function_name(7))
func_self=function_name
print(func_self(5))
function 可以以匿名函數(anonymous function)的方式通過參數傳遞:
--首先寫一個函數 有個2個參數 1是表 2是函數 --遍歷表 取出鍵值
--打印調用func將 鍵值作為參數傳遞進func
function anonymous(tab,func)
for k,v in pairs(tab) do
print(func(k,v))
end
end
--調用anonymous 1參傳入表,2參是匿名函數並且有執行內容,--內容是返回_k _v 注--意函數結尾需要有end
_table={key1="value1",key2="value2"}
anonymous(_table,function(_k,_v)
return _k,_v
end)
thread(線程)
在 Lua 里,最主要的線程是協同程序(coroutine)。擁有自己獨立的棧、局部變量和指令指針,可以跟其他協同程序共享全局變量和其他大部分東西。
線程跟協程的區別:線程可以同時多個運行,而協程任意時刻只能運行一個,並且處於運行狀態的協程只有被掛起(suspend)時才會暫停。
userdata(自定義類型)
userdata 是一種用戶自定義數據,用於表示一種由應用程序或 C/C++ 語言庫所創建的類型,可以將任意 C/C++ 的任意數據類型的數據(通常是 struct 和 指針)存儲到 Lua 變量中調用。(簡單來說就是在LUA中用userdata表示其他語言的數據類型)
Lua 變量
變量在使用前,必須在代碼中進行聲明,即創建該變量,Lua 中的變量全是全局變量,那怕是語句塊或是函數里,除非用 local 顯式聲明為局部變量,
局部變量的作用域為從聲明位置開始到所在語句塊結束,變量的默認值均為 nil。
variable_1=1 --全局
local variable_2 = 2 --局部
function function_name()
variable_3=3 --全局
local variable_4 = 4 --局部
return variable_3+variable_2--(注意 variable_2是在外面聲明的局部變量,本質也是全局的)
end
print(function_name())
print("variable_3="..variable_3)
print("variable_4=",variable_4)-- 注意不能使用".."連接一個空值
賦值語句
賦值是改變一個變量的值和改變表域的最基本的方法。
value=1
strValue="str"
value_2=value+2
print(strValue)
---------------------------------------------------------
_table={n="n_vale",m="m_value"}
print(_table.n)
_table.n=11
print(_table.n)
Lua 循環
很多情況下我們需要做一些有規律性的重復操作,因此在程序中就需要重復執行某些語句。
一組被重復執行的語句稱之為循環體,能否繼續重復,決定循環的終止條件。
循環結構是在一定條件下反復執行某段程序的流程結構,被反復執行的程序被稱為循環體。
循環語句是由循環體及循環的終止條件兩部分組成的。
while 循環
Lua 編程語言中 while 循環語句在判斷條件為 true 時會重復執行循環體語句。
語法
Lua 編程語言中 while 循環語法:(注意不同於C# 語句沒有大括號)
while(condition)
do
statements
end
statements(循環體語句) 可以是一條或多條語句,condition(條件) 可以是任意表達式,在 condition(條件) 為 true 時執
實例:
a=1
while( a < 5 )
do
print("a 的值為:", a)
a = a+1
end
Lua for 循環
Lua 編程語言中 for 循環語句可以重復執行指定語句,重復次數可在 for 語句中控制。
Lua 編程語言中 for語句有兩大類:(注意與C#的for 循環有較明顯區別)
第一種:數值for循環
for var=exp1,exp2,exp3 do
<執行體>
end
var從exp1變化到exp2,每次變化以exp3為步長遞增var,並執行一次"執行體"。exp3是可選的,如果不指定,默認為1。
實例:
for i=1,5 do
print(i)
end
---------------------------------------------------
function function_name(x)
return x*2
end
for i=1,function_name(3) do
print(i)
end
第二種:泛型for循環
泛型for循環通過一個迭代器函數來遍歷所有值
在lua中pairs與ipairs兩個迭代器的用法相近,但有一點是不一樣的:
pairs可以遍歷表中所有的key,包含索引,和自定義類型key
ipairs 僅可以遍歷出具備索引的值
_table2={"Suanday","Monday"}
_table2["ukey"]="uvalue" --鍵值都是字符串
intkey=8
_table2[intkey]="uvalue" --鍵是number 值是字符串
for k,v in ipairs(_table2) do
print(k,v)
end
輸出結果是 (table2 中僅具備索引的2個值被輸出了)
-- 1 Suanday
-- 2 Monday
for k,v in pairs(_table2) do
print(k,v)
end
輸出結果是(所有的鍵值均被輸出)
--1 Suanday
--2 Monday
--ukey uvalue
--8 uvalue
Lua break 語句
Lua 編程語言 break 語句插入在循環體中,用於退出當前循環或語句,並開始腳本執行緊接着的語句。
如果你使用循環嵌套,break語句將停止最內層循環的執行,並開始執行的外層的循環語句。
a=1
while(a<6)
do
print(a)
a=a+1
if(a>3)
then
break
end --注意if語句需要關鍵字 then和end
end --這個 end 是while 語句的結束
無限循環
在循環體中如果條件永遠為 true 循環語句就會永遠執行下去,以下以 while 循環為例:
while( true )
do
print("循環將永遠執行下去")
end
Lua if 語句
Lua if 語句 由一個布爾表達式作為條件判斷,其后緊跟其他語句組成。
Lua if 語句語法格式如下:
if(布爾表達式)
then
--[ 在布爾表達式為 true 時執行的語句 --]
end
a=1
if(a>0)
then
a=a+1
print(a)
end
if...else 語句
Lua if 語句可以與 else 語句搭配使用, 在 if 條件表達式為 false 時執行 else 語句代碼塊。
Lua if...else 語句語法格式如下:
if(布爾表達式)
then
--[ 布爾表達式為 true 時執行該語句塊 --]
else
--[ 布爾表達式為 false 時執行該語句塊 --]
end
if...elseif...else 語句
Lua if 語句可以與 elseif...else 語句搭配使用, 在 if 條件表達式為 false 時執行 elseif...else 語句代碼塊,用於檢測多個條件語句。
Lua if...elseif...else 語句語法格式如下:
if( 布爾表達式 1)
then
--[ 在布爾表達式 1 為 true 時執行該語句塊 --]
elseif( 布爾表達式 2)
then
--[ 在布爾表達式 2 為 true 時執行該語句塊 --]
elseif( 布爾表達式 3)
then
--[ 在布爾表達式 3 為 true 時執行該語句塊 --]
else
--[ 如果以上布爾表達式都不為 true 則執行該語句塊 --]
end
if...else 語句
Lua if 語句允許嵌套, 這就意味着你可以在一個 if 或 else if 語句中插入其他的 if 或 else if 語句。Lua if 嵌套語句語法格式如下:
if( 布爾表達式 1)
then
--[ 布爾表達式 1 為 true 時執行該語句塊 --]
if(布爾表達式 2)
then
--[ 布爾表達式 2 為 true 時執行該語句塊 --]
end
end
范例:
a=1
if(a>0) then a=a+1
if(a==2) then a=a+11
end
print(a)
end
Lua 函數
在Lua中,函數是對語句和表達式進行抽象的主要方法。既可以用來處理一些特殊的工作,也可以用來計算一些值。
Lua 提供了許多的內建函數,你可以很方便的在程序中調用它們,如print()函數可以將傳入的參數打印在控制台上。
Lua 函數主要有兩種用途:
1.完成指定的任務,這種情況下函數作為調用語句使用;
2.計算並返回值,這種情況下函數作為賦值語句的表達式使用
function returenMaxValue(v1,v2)
if(v1>v2)
then result=v1
else
result=v2
return result
end
end
print(returenMaxValue(11,19))
Lua 運算符
運算符是一個特殊的符號,用於告訴解釋器執行特定的數學或邏輯運算。Lua提供了以下幾種運算符類型:
- 算術運算符
- 關系運算符
- 邏輯運算符
- 其他運算符
算術運算符
下表列出了 Lua 語言中的常用算術運算符,設定 A 的值為10,B 的值為 20:
| 操作符 |
描述 |
實例 |
| + |
加法 |
A + B 輸出結果 30 |
| - |
減法 |
A - B 輸出結果 -10 |
| * |
乘法 |
A * B 輸出結果 200 |
| / |
除法 |
B / A w輸出結果 2 |
| % |
取余 |
B % A 輸出結果 0 |
| ^ |
乘冪 |
A^2 輸出結果 100 |
| - |
負號 |
-A 輸出結果v -10 |
關系運算符
下表列出了 Lua 語言中的常用關系運算符,設定 A 的值為10,B 的值為 20:
| 操作符 |
描述 |
實例 |
| == |
等於,檢測兩個值是否相等,相等返回 true,否則返回 false |
(A == B) 為 false。 |
| ~= |
不等於,檢測兩個值是否相等,相等返回 false,否則返回 true |
(A ~= B) 為 true。 |
| > |
大於,如果左邊的值大於右邊的值,返回 true,否則返回 false |
(A > B) 為 false。 |
| < |
小於,如果左邊的值大於右邊的值,返回 false,否則返回 true |
(A < B) 為 true。 |
| >= |
大於等於,如果左邊的值大於等於右邊的值,返回 true,否則返回 false |
(A >= B) 返回 false。 |
| <= |
小於等於, 如果左邊的值小於等於右邊的值,返回 true,否則返回 false |
(A <= B) 返回 true。 |
邏輯運算符
下表列出了 Lua 語言中的常用邏輯運算符,設定 A 的值為 true,B 的值為 false:
| 操作符 |
描述 |
實例 |
| and |
邏輯與操作符。 若 A 為 false,則返回 A,否則返回 B。 |
(A and B) 為 false。 |
| or |
邏輯或操作符。 若 A 為 true,則返回 A,否則返回 B。 |
(A or B) 為 true。 |
| not |
邏輯非操作符。與邏輯運算結果相反,如果條件為 true,邏輯非為 false。 |
not(A and B) 為 true。 |
其他運算符
下表列出了 Lua 語言中的連接運算符與計算表或字符串長度的運算符:
| 操作符 |
描述 |
實例 |
| .. |
連接兩個字符串 |
a..b ,其中 a 為 "Hello " , b 為 "World", 輸出結果為 "Hello World"。 |
| # |
一元運算符,返回字符串或表的長度。 |
#"Hello" 返回 5 |
Lua 字符串
字符串或串(String)是由數字、字母、下划線組成的一串字符。
Lua 語言中字符串可以使用以下三種方式來表示:
單引號間的一串字符。
雙引號間的一串字符。
和[[ ]]間的一串字符。
范例:
str_1="stringtype_1"
str_2='stringtype_2'
str_3=[["stringtype_3"]]
print(str_1)
print(str_2)
print(str_3)
字符串操作
result=string.upper("upper") //字符串轉大寫
print(result)
result=string.lower("LOWER")//字符串轉小寫
print(result)
result=string.reverse("reverse ")//字符串翻轉
print(result)
result=string.len("len")//字符串長度
print(result)
字符串格式化
Lua 提供了 string.format() 函數來生成具有特定格式的字符串, 函數的第一個參數是格式 , 之后是對應格式中每個代號的各種數據。
字符串格式化
str_1="aaa"
str_2="bbb"
result =string.format("%s,%s",str_1,str_2)
print(result)
日期格式化:
day=1
month=5
year=2017
date=string.format("日期:%02d/%02d/%03d",day,month,year)
print(date)
Lua 數組
數組,就是相同數據類型的元素按一定順序排列的集合,可以是一維數組和多維數組。
Lua 數組的索引鍵值可以使用整數表示,數組的大小不是固定的。
array={"hu","hj"}
for i=0,2 do
print(array[i])
end
--nil
-- hu
-- hj
-- 我們發現上述代碼,索引為0時,從輸出了nil lua數組索引默認為1.
正如你所看到的,我們可以使用整數索引來訪問數組元素,如果知道的索引沒有值則返回nil。
在 Lua 索引值是以 1 為起始,但你也可以指定 0 開始。
除此外我們還可以以負數為數組索引值:
array={}
for i=-10,0 do
array[i]=i*2
print(array[i])
end
多維數組
array={}
for i=1,3 do
array[i]={}
for j=1,3 do
array[i][j]=i*j
end
end
for i=1,3 do
for j=1,3 do
print(array[i][j])
end
end
-- 123
-- 246
-- 369
Lua 迭代器
泛型 for 迭代器
泛型 for 在自己內部保存迭代函數,實際上它保存三個值:迭代函數、狀態常量、控制變量。
泛型 for 迭代器提供了集合的 key/value 對,語法格式如下:
for k, v in pairs(t) do
print(k, v)
end
范例代碼:
table={"huhu","jack","ukraine"}
for k,v in pairs(table) do
print(k,v)
end
Lua table(表)
table 是 Lua 的一種數據結構,用來幫助我們創建不同的數據類型,如:數字、字典等。
Lua table 使用關聯型數組,你可以用任意類型的值來作數組的索引,但這個值不能是 nil。
Lua table 是不固定大小的,你可以根據自己需要進行擴容。
table(表)的構造
構造器是創建和初始化表的表達式。表是Lua特有的功能強大的東西。最簡單的構造函數是{},用來創建一個空表。
-- 初始化表
mytable = {}
-- 指定值
mytable[1]= "Lua" --使用數字作為鍵
table["strKey"]="value" --使用字符串作為鍵的寫法1
table.strKey="value" --使用字符串作為鍵的寫法2
-- 移除引用
mytable = nil
-- lua 垃圾回收會釋放內存
范例代碼-1:
table={"value1","value2"}
table["other1"]="other_value1"
table["other2"]=" other_value2"
for k,v in pairs(table) do
print(k,v)
end
--1 value1
--2 value2
--other1 other_value1
--other2 other_value2
范例代碼-2:
m_table={"a","b","c"}
print("m_table類型是=",type(m_table))
temp_table=m_table
print("temp_table指向m_table,temp_table[1]=",temp_table[1])
temp_table[1]="aa" --修改m_table[1]的值
temp_table=nil
print("釋放temp_table后 m_table[1]=",m_table[1])
Table連接:
m_table={"a","b","c"}
temp=table.concat(m_table) --注意table是關鍵字
print(temp)
插入和移除:
插入:
m_table={"a","b","c"}
table.insert(m_table,"d")
print(m_table[4])
移除:
table.remove(m_table) --移除方法,會移除最后一個元素
for k,v in pairs(m_table) do
print(k,v)
end
排序:
字母排序:
str={"a","d","b","c"}
for k,v in pairs(str) do
print("排序前:"..k..":"..v)
end
table.sort(str)
for k,v in pairs(str) do
print("排序后:"..k..":"..v)
end
數字排序:
a=1
b=2
c=3
d=4
str={a,d,b,c}
for k,v in pairs(str) do
print("排序前:"..k..":"..v)
end
table.sort(str)
for k,v in pairs(str) do
print("排序后:"..k..":"..v)
end
