Programming in Lua (基礎篇)

來源:互聯網
上載者:User

2012-04-02 wcdj

$ lua -v

Lua 5.2.0 Copyright (C) 1994-2011 Lua.org, PUC-Rio

目錄

0 什麼是Lua?... 1

1 Lua簡單介紹... 1

2 基本文法... 3

3 函數... 4

4 實踐代碼... 6

5 參考:... 14

 

0 什麼是Lua?

Lua本身是以簡單優雅為本,著眼於處理那些C不擅長的任務;

Lua本身完全遵循ANSI C而寫成,只要有C編譯器的地方,Lua便可發揮她的力量;

對那種在產品的生命週期內變化比較多的應用方向,使用Lua可以更方便的適應變化;

Lua有很高的執行效率,統計表明Lua是目前平均效率最高的指令碼語言;

Lua的使用者分為三類:使用Lua嵌入到其他應用中的、獨立使用Lua的、將Lua和C混合使用的;

1 Lua簡單介紹

n  和其他指令碼一樣,Lua有兩種執行方式。

(1) 命令列互動式。即不帶參數運行,使用檔案結束符退出Ctrl-D in Unix, Ctrl-Z in DOS/Windows,或者調用os.exit()退出。

(2) 呼叫指令碼執行(帶指令檔參數運行)。

(3) 在命令列互動過程中,可以使用dofile函數調用外部的指令檔來載入需要的library。

n  Lua是動態類型語言,變數不用類型定義。

全域變數不需要聲明,給一個變數賦值後即建立了這個全域變數。訪問一個沒有初始化的全域變數也不會出錯,只是得到結果為 nil。若且唯若一個變數不等於nil時,這個變數才存在。

Lua中有8個基本類型:

nil, boolean, number, string, userdata,function, thread, table

注意:

(1) 函數type可以測試給定變數或值的類型。

(2) 變數沒有預定義的類型,每一個變數都可能包含任一種類型的值。

(3) 可以使用函數像使用其他值一樣使用(將一個函數賦值給一個變數)。

(4) nil是Lua中特殊的類型,一個全域變數沒有被賦值以前預設值為nil;給全域變數賦值為nil可以刪除該變數。

(5) boolean有兩個取值false和true。Lua中所有的值都可以作為條件。在控制結構的條件中除了false和nil為假,其他值都為真。所以,Lua認為0和空串都是真。

(6) number表示實數,Lua中沒有整數。Lua的number可以處理任何長整數不用擔心誤差。

(7) string指字元的序列。string和其他對象一樣,Lua自動進行記憶體配置和釋放,一個string可以只包含一個字母也可以包含一本書,Lua可以高效地處理長字串,1M的string在Lua中是很常見的。可以使用單引號或雙引號表示字串。為了風格統一,最好使用一種,除非兩種引號嵌套情況,對於字串中含有引號的情況還可以使用轉義符\來表示。

(8) Lua中的逸出序列和C語言中類似,特殊的有:

\[ 左中括弧

\] 右中括弧

(9) 還可以使用 [[...]] 表示字串。這種形式的字串可以包含多行,可以嵌套且不會解釋逸出序列。這種形式的字串用來包含一段代碼是非常方便的。

(10) Lua會自動在string和number之間自動進行類型轉換,當一個字串使用算術操作符時,string就會被轉成數字。反之,當Lua期望一個string而碰到數字時,會將數字轉成string。

Note: 儘管字串和數字可以自動轉換,但兩者是不同的,像 10 == "10" 這樣的比較永遠都是錯的(比較的時候,不會自動轉換,需要顯示轉換!)。如果需要顯示將string轉成數字可以使用函數tonumber(),如果string不是正確的數字該函數將返回nil。反之,可以調用tostring()將數字轉成字串。

(11) .. 在Lua中是字串串連符,當在一個數字後面寫 .. 時,必須加上空格以防止被解釋出錯。

(12) Function和其他變數相同,函數可以儲存在變數中,可以作為函數的參數,也可以作為函數的傳回值。(這個特性給了Lua很大的靈活性:一個程式可以重新定義函數增加新的功能或者為了避免運行不可靠代碼建立安全運行環境而隱藏函數)

(13) Userdata可以將C資料存放在Lua變數中,userdata在Lua中除了賦值和相等比較外沒有預定義的操作。Userdata用來描述應用程式或者使用C實現的庫建立的新類型。

n  任何一門語言都有詞法約定。

Lua的標識符約定與C語言相同。

注意:

(1) Lua的保留字,不能當作標識符。

and; break; do; else; elseif; end;false; for; function; if; in; local; nil; not; or; repeat; return; then; true;until; while;

(2) Lua是大小寫敏感的。

(3) 單行注釋的方法:--

(4) 多行注釋的方法:--[[    --]]

n  一些常用的命令列選項

-e                  直接將命令傳入Lua

-l                   載入一個檔案

-i                   進入互動模式

-PROMPT      內建變數作為互動模式的提示符      

注意:

全域變數arg存放Lua的命令列參數。在運行以前,Lua使用所有構造參數構造arg表,指令碼名索引為0,指令碼的參數從1開始增加。指令碼前面的參數從-1開始減少。

n  運算式

Lua中的運算式包括:數字常量、字串常量、變數、一元和二元運算子、函數調用。

(1) 算術運算子

二元運算子:+ - * /^ 加減乘除冪

一元運算子:- 負值

這些運算子的運算元都是實數。

(2) 關係運算子

<  >   <=   >=   ==   ~=

(3) 邏輯運算子

and  or   not

注意:

邏輯運算子認為false和nil是假(false),其他為真(0也是真)。

a and b

如果a為false,則返回a,否則返回b

a or b

如果a為true,則返回a,否則返回b

C語言中的三元運算子

A ? B : C

在Lua中可以實現為:

(A and B) or C

not的結果一直返回false或者true。

(4) 串連運算子

..   兩個點

注意:

字串串連,如果運算元為數字,Lua將數字轉成字串。

n  表的構造(table)

構造器是建立和初始化表的運算式。表是Lua特有的功能強大的東西。最簡單的建構函式是{},用來建立一個空表。可以直接初始化數組。

注意:

(1) 不推薦數組下標從0開始,否則很多標準庫不能使用。

(2) 在建構函式的最後的“,”是可選的,可以方便以後的擴充。

(3) 在建構函式中域分隔字元逗號可以用分號代替,通常使用分號來分割不同類型的表元素。

2 基本文法

 

n  指派陳述式

Lua可以對多個變數同時賦值,變數列表和值列表的各個元素用逗號分開,指派陳述式右邊的值會依次賦給左邊的變數。(遇到指派陳述式,Lua會先計算右邊所有的值,然後再執行賦值操作)

注意:

當變數個數和值的個數不一致時,Lua會一直以變數個數為基礎採取以下策略:

A. 變數個數 > 值的個數 (按變數個數補足nil)

B. 變數個數 < 值的個數 (多餘的值會被忽略)

Note: 如果要對多個變數賦值,必須依次對每個變數賦值(常見錯誤)。

n  局部變數與代碼塊

使用local建立一個局部變數。與全域變數不同,局部變數只在被聲明的那個代碼塊內有效。

應該儘可能使用局部變數:

(1) 避免命名衝突;

(2) 訪問局部變數的速度比全域變數更快;

可以給block劃定一個明確的界限:

do .. end 內的部分(當想更好地控制局部變數的範圍的時候這是很有用的)

n  控制結構語句

(1) if有3種形式

(2) while語句

(3) repeat-until語句

(4) for有2種形式

A: 數值for迴圈

for var = exp1, exp2, exp3 do

Loop-part

end

for將用exp3作為step從exp1(初始值)到exp2(終止值),執行loop-part。其中,exp3可以忽略,預設step = 1。

注意:

(1) for中的三個運算式只會被計算一次,並且是在迴圈開始前。

(2) 控制變數var是局部變數自動被聲明,並且只在迴圈內有效。

(3) 如果需要保留控制變數的值,需要在迴圈中將其儲存。

(4) 迴圈過程中不要改變控制變數的值,那樣做的結果是不可預知的。如果要退出迴圈,使用break語句。

B:範型for迴圈

for i, val in ipairs(a) do print(v) end

範型for遍曆迭代子函數返回的每一個值(val)。

3 函數

注意:

(1) 調用函數的時候,如果參數列表為空白,必須使用()表明是函數調用。但是,當函數只有一個參數並且這個參數是字串或者表結構的時候,()是可選的。

(2) Lua也提供了物件導向方式調用函數的文法,比如o:foo(x)與o.foo(o, x)是等價的。

(3) Lua使用的函數可以是Lua編寫的也可以是其他語言編寫的,對於Lua程式員來說用什麼語言實現的函數使用起來都一樣。

(4) Lua函數實參和形參的匹配與指派陳述式類似,多餘部分被忽略,缺少部分用nil補足。

(5) Lua函數可以返回多個結果值。比如,string.find,其返回匹配串開始和結束的下標,如果不存在匹配串返回nil。Lua函數中,在return後列出要返回的值的列表即可返回多值。

Note:

return f() 這種類型返回f()返回的所有值;

print((foo())) 可以使用圓括弧強制使調用返回一個值;

(6) 函數多值返回的特殊函數unpack,其接受一個數組作為輸入參數,返回數組的所有元素。

(7) Lua函數可以是可變參數,和C語言類似在函數參數列表中使用“...”表示函數有可變的參數。Lua將函數的參數放在一個arg的表中,除了參數以外,arg表中還有一個域n表示參數的個數。

(8) 具名引數

 

再論函數

 

(1) 閉包

當一個函數內部嵌套另一個函數定義時,內部的函數體可以訪問外部的函數的局部變數,這種特徵我們稱作詞法定界。

(2) 非全域函數(局部函數)

Lua中函數可以作為全域變數也可以作為局部變數。函數作為表table的域:

A: 表和函數放在一起

B: 使用表建構函式

 

 Lib_wcdj = {}

 Lib_wcdj.add = function (x, y) return x + yend

 Lib_wcdj.subtract = function (x, y) return x -y end

 

 Lib_gerry = {

    multiply = function (x, y) return x * y end,

    divide = function (x, y) return x / y end

 }

 print(Lib_wcdj.add(1, 2))

 print(Lib_wcdj.subtract(1, 2))

 print(Lib_gerry.multiply(2, 3))

 print(Lib_gerry.divide(5, 2))

 

 --[[

 3

 -1

 6

 2.5

 --]]

 

(3) 正確的尾調用

尾調用是一種類似在函數結尾的goto調用,當函數最後一個動作是調用另外一個函數時,稱這種調用為尾調用。例如:g的調用是尾調用

function f(x)

return g(x)

end

f調用g後不會再做任何事情,這種情況下當被調用函數g結束時,程式不需要返回到調用者f,所以尾調用之後程式不需要在棧中保留關於調用者的任何資訊。一些編譯器比如Lua解譯器利用這種特性在處理尾調用時,不使用額外的棧,稱這種語言支援正確的尾調用。由於尾調用不需要使用棧空間,那麼尾調用遞迴的層次是可以無限制的,不會導致棧溢出。

注意:

必須明確什麼情況屬於尾調用。

4 實踐代碼

--[[test.lua 2012-04-02 wcdj-- --]]-- defines a factorial functionfunction fact (n)if n == 0 thenreturn 1elsereturn n*fact(n-1)endendfunction norm(x, y)local n2 = x^2 + y^2return math.sqrt(n2)endfunction twice (x)return 2*xendprint("enter a number: ")input = io.read() -- read a numberdata_in = tonumber(input)if data_in == nil thenprint("invalid number")elseprint(fact(data_in))endprint(tostring(10) == "10") -- trueprint(10 .. "" == "10")-- true--[[arg[-3] = "lua"arg[-2] = "-e"arg[-1] = "sin=math.sin"arg[0]  = "script"arg[1]= "a"arg[2]  = "b"--]]--[[print(arg[-3])print(arg[-2])print(arg[-1])print(arg[0])print(arg[1])print(arg[2])print(arg[3])--]]print(type("Hello world"))print(type(10.4*3))print(type(print))print(type(type))print(type(true))print(type(nil))print(type(type(X)))--[[stringnumberfunctionfunctionbooleannilstring--]]print(type(a))a = 10print(type(a))a = "a string !"print(type(a))a = printprint(type(a))a(type(a))--[[nilnumberstringfunctionfunction--]]a = "one string"-- change string partsb = string.gsub(a, "one", "another")print(a)print(b)--[[one stringanother string--]]print("10" + 1)print("10 + 1")-- error-- print("hello" + 1)--[[1110 + 1--]]print(10 .. 20)-- malformed number near '10..20'-- print(10..20)print("I'm " .. 10 .. " years old!")--[[1020I'm 10 years old!--]]print(4 and 5)print(nil and 6)print(false and 13)print(4 or 5)print(false or 5)--[[5nilfalse45--]]print(not nil)print(not false)print(not 0)print(not not nil)--[[truetruefalsefalse--]]print("Hello " .. "World")print(0 .. 1)--[[Hello World01--]]days = {"Sunday", "Monday", "Tuesday", "Wednesday","Thursday","Friday","Saturday",}print(days[4])a = {x = 100, y = 200; "one", "two", "three"}print(a.x)print(a[0])print(a[1])print(a[3])print(a[4])b = {}b.x = 300b.y = 400print(b.x)--[[Wednesday100nilonethreenil300--]]a, b, c = 10, 2^4, "wcdj"print(a)print(b)print(c)a, b, c = 0print(a)print(b)print(c)--[[1016wcdj0nilnil--]]-- swapx = 1y = 3x, y = y, xprint(x)print(y)--[[31--]]x = 100if "wcdj" ~= "gerry" thenlocal xx = 1;print(x)elseprint(x)endprint(x)--[[1100--]]x = 100local x = 1print(x)dolocal x = 2print(x)endprint(x)--[[121--]]print(8*9, 1/3)a = math.sin(3) + math.cos(10)print(os.date())--[[72      0.33333333333333Mon Apr  2 14:54:02 2012--]]print "Hello World"print [[My name is wcdj]]--[[Hello WorldMy name is wcdj--]]a, b = string.find("hello Lua users", "Lua")print(a, b)--[[7       9--]]function maximum(a)local max_idx = 1local max = a[max_idx]for i, val in ipairs(a) doif val > max thenmax_idx = imax = valendendreturn max, max_idxendprint(maximum({8, 10, 23, 12 ,5}))print(maximum{8, 10, 23, 12 ,5})--[[23      323      3--]]function newCounter()local i = 0return function() -- anonymous functioni = i + 1return iendendadd = newCounter()print(add())print(add())--[[12--]]Lib_wcdj = {}Lib_wcdj.add = function (x, y) return x + y endLib_wcdj.subtract = function (x, y) return x - y endLib_gerry = {multiply = function (x, y) return x * y end, divide = function (x, y) return x / y end}print(Lib_wcdj.add(1, 2))print(Lib_wcdj.subtract(1, 2))print(Lib_gerry.multiply(2, 3))print(Lib_gerry.divide(5, 2))--[[3-162.5--]]

5 參考:

[1] Programming in Lua

[2] Lua 5.2 Reference Manual http://www.lua.org/manual/5.2

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.