lua程序设计
1.基本
(1)a=10?? --定義一個全局變量
?? a=nil? --刪除一個全局變量
(2)print("hello","world")?????? --中間有空格,后面有換行
?? io.write("hello","world")??? --中間無空格,后面無換行
?? a=io.read("input a number:") --從標準輸入讀入一個數據
(3)Chunk 是指lua的一系列語句,lua每一個語句后面的";"是可選的。
?? os.exit()退出當前程序的運行
?? lua -l file1 -l file2 --將2個文件連接(拼接在一起)在一起運行,先運行file1在運行file2,file1中的變量對file2可見
?? dofile("file.lua")? --在內存中運行file.lua文件,并在內存中保存所以變量??梢砸源朔绞郊虞d函數庫。
(4)lua的所有保留字:and,break,do,else,else,ifend,false,for,function,if,in,local,nil,not,or,repeat,return,then,true,until,while.
?? --[[? ...? --]]? :表示多行注釋
(5)lua [options] [script [args]]???? lua的命令運行方式
?? -e:直接將命令傳入Lua?????? lua -e "print(math.sin(12))"? 可以通過-e選項向腳本傳遞全局變量值
?? -l:鏈接加載運行一個文件.?? lua -l file1?? file?? 相當于把file1作為file的庫使用
?? -i:進入交互模式.
?? 系統默認的全局變量arg通過數組的形式存放命令行參數,arg[1]為第一個參數,命令行參數以空格為分隔,且命令行參數都是字符串形式的。
(6)lua的數據類型:lua是動態類型的語言,變量不需要指定類型,lua會自動根據變量的值判斷變量的類型。
?? lua中有8個基本類型分別為:nil、boolean、number、string、userdata、function、thread 和table。
?? boolean類型有2個取值true和false。在lua條件判斷中,false和nil為假,其它都為真(包括0和空串),存在即為真。
?? type可以測試給定變量或者值的類型。
?? print(type("Hello world")) --> string
?? print(type(print)) --> function
?? 不同數據類型的值可能可以做數值運算(+-*/)因為數學運算符有隱形的數據轉換,但是切記不要做關系和邏輯運算。tostring(),tonumber()函數可以轉換number和string類型。
?? .. 連接運算符,不管連接的哪種數據類型,最后生成的數據都是string類型。注意“ .. ”使用時前后都要加空格。
?? print(type(10 .. 20)) --> string
?? function類型:函數和其他變量相同是一種數據類型,意味著函數可以存儲在變量中,可以作為函數的參數和返回值。這個特性給了語言很大的靈活性。
?? lua的5大標準庫包括string庫、table庫、I/O庫、OS庫、算術庫、debug庫。
?? userdata和thread類型:userdata可以將C數據存放在Lua 變量中。userdata在Lua中除了賦值和相等比較外沒有預定義的操作。
(7)lua的表達式:Lua 中的表達式包括數字常量、字符串常量、變量、一元和二元運算符、函數調用以及表構造。
?? 關系運算符:< > <= >= == ~=? 在做關系運算的時候,最好確保使用的數據類型是相同的。
?? 邏輯運算符:and or not
?? .. :連接運算符,總是返回string類型的值。
?? 表的構造:表構造器是指初始化表的表達式。(3種表:下標表,鍵值表,成員表)
?? 默認下標索引構造法:days = {"Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"}
?? 成員索引構造法:a = {x=0, y=0}? a = {}; a.x=0; a.y=0;a.y=nil??? --可以刪除表元素。
?? 關鍵字索引構造法:a = {["lk"]="red",["lm"]="green",["ln"]="blue"}? 關鍵字必須加引號,除非關鍵字是數字
?? 混合索引構造法:a = {"red",x=3,"green","blue"}相當于a = {[1]="red",x=3,[2]="green",[3]="blue"}?? print(a[3]) -->blue
?? 表的引用:下標、關鍵字和成員索引。默認下標是從1開始的,有關鍵字的元素不能用關鍵字索引,構造表中沒有關鍵字的那么默認關鍵字從[1]開始。
?? 構造表中的分割號既可以是","也可以是";"
?? [[]]支持以可換行的方式創建表,便于閱讀。
(8)lua的賦值
?? 多值賦值:
?? a, b = 10, 2*x <--> a=10; b=2*x
?? a, b, c = 0,1;print(a,b,c) --> 0 1 nil
?? 多值賦值可以用在函數的返回值中。
(9)lua的局部變量
?? 用local申明一個局部變量,局部變量只能在申明的那個代碼塊內使用。
?? 代碼塊指:一個控制結構(控制結構的范圍是do...end;then...end之間);一個函數體;一個chunk(變量被申明的那個文件或者文本串)
? local x;
?? local y=1;
(10)lua的控制結構
?if語句:
?if conditions then
?????? then-part
?? elseif conditions then
?????? elseif-part
?? else
?????? else-part
?? end;
?while語句:
?while condition do
?? statements;
?end;
repeat語句:
?repeat
?? statements;
?until conditions;
數值for循環:
?for var=forstart,forend,step do
?? loop-part
?end
范型for循環:
for i,v in ipairs(t) do print(v) end? -->打印表中所有的值
for k in pairs(t) do print(k) end???? -->打印表中所有的鍵
(11)break和return語句
break 語句用來退出當前循環(for、repeat、while)
return 用來從函數返回結果,當一個函數自然結束時,結尾會有一個默認的return。
Lua 語法要求break 和return 只能出現在block 的結尾一句(也就是說:作為chunk的最后一句,或者在end 之前,或者else 前,或者until 前),
有時候為了調試或者其他目的需要在block 的中間使用return 或者break,可以顯式的使用do..end 來實現:
function foo ()
return --<< SYNTAX ERROR? 'return' is the last statement in the next block
do return end -- OK
... -- statements not reached
end
2.lua函數
(1).定義
function func_name (arguments-list)
? statements-list;
end;
(2)函數的可變參數列表
function print(...)
--對下標索引表arg進行操作
end
可以使用"..."表示函數的可變參數列表,函數的可變參數放在"下標索引"表arg中。
string.find("hello hello", " hel")在字符串中查找子串,返回子串起始位置和結束位置。
string.format("first is :%d;%f", y, x))
unpack(t) 能解包t表中以小標為索引的元素。 t={["k"]=1,2,3} print(unpack(t)) -->2 3
(3)函數的高級特性
a.函數實際是一個普通的變量,變量類型為function類型
function foo (x) return 2*x end
等價于
foo = function (x) return 2*x end
b.閉包
特定:返回一個函數;外部函數為內部函數提供了參數保存(保存內部函數的狀態),使得內部函數的調用具有了"記憶"功能。
可以用來實現迭代器以及泛型for
function list_iter (t)
local i = 0
local n = table.getn(t)
return function ()
i = i + 1
if i <= n then return t[i] end
end
end
使用迭代器:
t = {10, 20, 30}
iter = list_iter(t) -- creates the iterator
while true do
local element = iter() -- calls the iterator
if element == nil then break end
print(element)??
end
迭代器用于范性for:
t = {10, 20, 30}
for element in list_iter(t) do
print(element)
end
c.非全局函數(表的成員函數)
Lib = {}
Lib.foo = function (x,y) return x + y end
或
Lib = {}
function Lib.foo (x,y)
return x + y
end
d.正確的尾部調用(尾部遞歸)
function f(x)
return g(x)
end
f調用g后不會再做任何事情,這種情況下當被調用函數g 結束時程序不需要返回到調用者f;所以尾調用之后程序不需要在棧中保留關于調用者的任何信息。一些編譯器比如Lua 解釋器利用這種特性在處理尾調用時不使用額外的棧,我們稱這種語言支持正確的尾調用。節省了棧開銷。
3.編譯·運行·錯誤信息
a.加載文件和字符串表達式(編譯)
dofile("文件路徑")?? 加載并全局運行該文件
f=loadfile("文件路徑") 加載但并不運行文件,返回一個文件內容的全局調用地址,可以像函數一樣調用。
f=loadstring("表達式") 加載表達式,但不調用。
b.例子
b.1?
dofile的真正實現為:由loadfile實現
function dofile (filename)
? local f = assert(loadfile(filename))
? return f()
end
b.2
f = loadstring("i = i + 1")
i = 0
f(); print(i) --> 1
f(); print(i) --> 2? 將字符串當作表達式來執行。
b.3
Lua 把每一個chunk都作為一個匿名函數處理。例如:chunk "a = 1",loadstring 返回與其等價的function() a = 1 end
與其他函數一樣,chunks 可以定義局部變量也可以返回值:
f = loadstring("local a = 10; return a + 20")
print(f()) --> 30
c.require加載
Lua 提供高級的require 函數來加載運行庫。粗略的說require 和dofile 完成同樣的功能但有兩點不同:
1) require 會搜索目錄加載文件
2) require 會判斷是否文件已經加載避免重復加載同一文件。由于上述特征,require在Lua 中是加載庫的更好的函數。
require指定lua的加載路徑。
4.lua中使用table來實現其他數據結構
table是Lua中唯一的數據結構,其他語言所提供的數據結構,如:arrays、records、lists、queues、sets 等,Lua 都是通過table 來實現,并且在lua 中table 很好的實現了這些數據結構。
5.lua dofile調用時產生的事件,及其回調
文件 data.lua
Entry{"Donald E. Knuth",?????? --記住Entry{...}與Entry({...})等價,他是一個以表作為唯一參數的函數調用。
????? "Literate Programming",? --指示Entry()函數的入參可能的取值
????? "CSLI",????????????????? --這其實是一個無名表
????? 1992}
Entry{"Jon Bentley",
????? "More Programming Pearls",
????? "Addison-Wesley",
????? 1990}
主文件
local authors = {} -- a set to collect authors
function Entry (b) authors[b[1]] = true end
dofile("data")?? --當每加載一個Entry數據項時,就調用一次該文件中的Entry()函數。
for name in pairs(authors) do print(name) end
在這些程序段中使用事件驅動的方法:Entry 函數作為回調函數,dofile 處理數據文件中的每一記錄都回調用它。
6.lua的6大標準庫
math:
sin,cos,tan,asin,acos,exp,log,log10,floor,ceil,max,min,random
table:getn(有n成員時,返回n的值;沒有n成員時,返回元素個數),setn(設置n成員的值)
????? insert(t, a)向表t中尾部插入一個元素a;table.remove(t)尾部刪除一個元素;
????? table.insert(t,1,a)和table.remove(t,1) 首部插入和首部刪除
string:string.len(s);string.rep(s,n)使用s生成一個重復n次的字符串;string.lower(s);string.upper(s)
?????? string.sub(s,i,j)切片(i,j=-1指向最后一個字符,-2 指向倒數第二個)
?????? string.char(97) string.byte("a") ASCII數字與字符相互轉換
?????? string.format("pi = %.4f", PI))格式化字符串
?????? string.find(s,"ab",0)? 第一個子字符串查找 。第二個參數可以是一個模式,比如"%d"查找一個數字,%a一個字母
?????? string.gsub(s,"a","b") 全局字符串替換?????? 第二個參數可以是一個模式,比如"%d"查找一個數字,%a一個字母
?????? string.gfind?????????? 全局字符串查找?????? 第二個參數可以是一個模式,比如"%d"查找一個數字,%a一個字母
IO:?? lua使用當前文件的概念,io.read,io.write,print都是從當前文件中讀寫,默認當前文件為stdin和stdout
?????? io.input("filename")?? 改變當前輸入文件?
?????? io.output("filename")? 改變當前輸出文件?
?????? io.read("*all") 讀取整個文件;"*line":讀取下一行;? "*number":從串中轉換出一個數值;?? num:讀取num個字符
?????? io.lines()讀下一行(是一個迭代器)
?????? f=io.open("filename", "w")? -> f:read("*all")
OS:??? os.time{year=1970, month=1, day=1, hour=0}) 返回時間戳
?????? os.date()
?????? os.getenv("HOME")
?????? os.execute("mkdir? filename")
Debug:
?????? debug.getinfo(funcname)? 返回函數的所有屬性
7.lua中的棧
C API包括讀寫Lua全局變量的函數,調用Lua函數的函數,運行Lua 代碼片斷的函數,注冊C函數然后可以在Lua中被調用的函數等。在C 和Lua 之間通信關鍵內容在于一個虛擬的棧。棧的使用解決了C 和Lua 之間兩個不協調的問題:第一,Lua 會自動進行垃圾收集,而C 要求顯示的分配存儲單元,兩者引起的矛盾。第二,Lua 中的動態類型和C 中的靜態類型不一致引起的混亂。
lua的棧
? ? ? ? ? ? -------------------------
棧頂 indx=-1-> | Dn | ... | D2 | D1-> ? 棧底 ?indx=1 ?
? ? ? ? ? ? -------------------------
lua的棧類似于以下的定義, 它是在創建lua_State的時候創建的: ?
TValue stack[max_stack_len] #max_stack_len默認=20
存入棧的數據類型包括數值, 字符串, 指針, talbe, 閉包等, 下面是一個棧的例子:
? ? ? ? ? ? ? ? ? ? ? ??
執行下面的代碼就可以讓你的lua棧上呈現圖中的情況
lua_pushcclosure(L, func, 0) // 創建并壓入一個閉包 ??
lua_createtable(L, 0, 0) ? ? ? ?// 新建并壓入一個表 ??
lua_pushnumber(L, 234) ? ? ?// 壓入一個數字 ??
lua_pushstring(L, “mystr”) ? // 壓入一個字符串 ?
壓入的類型有數值, 字符串, 表和閉包在c中看來是不同類型的值, 但是最后都是統一用TValue這種數據結構來保存的.?
TValue結構對應于lua中的所有數據類型, 是一個{值, 類型} 結構,保存在棧的的數據根據8大數據類型不同保存的方式不一樣,分2種:值保存和指針保存。
? a. lua中, number, boolean, nil, light userdata四種類型的值是直接存在棧上元素里的, 和垃圾回收無關.
? b. lua中, string, table, closure, userdata, thread存在棧上元素里的只是指針, 他們都會在生命周期結束后被垃圾回收.
8.lua與C語言交互的函數集-C API
主要的CAPI庫函數
<lua.h>、<lauxlib.h>、<lualib.h>
lua_State *L = lua_open()? --打開lua運行環境,返回lua_State *運行環境指針。并沒有加載任何庫
luaopen_base(L);?????????? --打開基本庫
luaopen_table(L);????????? --打開表庫
luaopen_io(L);???????????? --打開io庫
luaopen_string(L);???????? --打開字符串庫
luaopen_math(L);?????????? --打開數學庫
error = luaL_loadbuffer(L, "a=a+1", strlen("a=a+1"),"line")???
編譯字符串,如果成功,則將其放入棧中;否則返回錯誤信息,并壓入棧中。
error = luaL_loadfile(L, "filename")
編譯文件,如果成功,則將其放入棧中;否則返回錯誤信息,并壓入棧中。
lua_close(L); --關閉lua環境
void lua_call(lua_State* L, int nargs, int nresults)非保護下調用一個lua函數。調用它之前, 需要布局一下棧, 第一, 要把要call的函數壓入棧; 第二, call要用的參數正序壓入棧中; 然后才能調用lua_call, 調用完了, 自己去取返回值, 它都給你壓棧上了.
error = lua_pcall(L,?int nargs,int nresults, int ferror); ?出棧指定位置的數據,并在lua環境中運行,運行后保存所以全局變量。如果出錯,則將錯誤信息壓棧。正確調用將返回0
C語言中調用的壓棧函數?
a.將C環境的數據類型壓入棧的函數
void lua_pushnil (lua_State *L);
void lua_pushboolean (lua_State *L, int bool);
void lua_pushnumber (lua_State *L, double n);
void lua_pushlstring (lua_State *L, const char *s,size_t length);
void lua_pushstring (lua_State *L, const char *s);
int lua_checkstack (lua_State *L, int sz); 檢測棧上是否有足夠你需要的空間
void lua_getfield (lua_State *L, int index, const char *k) ?
取由index指向的棧上的一個表的鍵為k的元素的值,并壓入棧頂
void lua_setfield (lua_State *L, int index, const char *k)?
給由index指向的棧上的一個表的鍵為k的元素賦值,被賦的值是棧頂的值。
void lua_gettable (lua_State *L, int index)
根據index指定取到相應的表; 取棧頂元素為key, 并彈出棧; 獲取表中key的值壓入棧頂.
void lua_settable (lua_State *L, int index)
根據index指定取到相應的表; 取棧頂元素做value, 彈出之; 再取當前棧頂元素做key, 亦彈出之; 然后將表的鍵為key的元素賦值為value
b.將lua環境中的變量壓入棧中
lua_getglobal(L, "變量名"); --變量名可以是:普通變量,表,函數等任何全局變量
lua_gettable(L, inx);?????? --獲取棧中inx元素(表),以inx-1為鍵對應表中的值,并將值放在inx-1位置。(所以用戶要獲得表中某成員的值,應該先將該成員名壓入到棧中)
lua_setglobal(L,"變量名");? --將棧中的某變量賦值給lua環境中的"變量名"變量。
c.判斷棧中指定位置的元素數據類型的C函數
int lua_type(lua_State *L, int index); )返回lua 8大數據類型對應的類型碼。在lua.h 頭文件中,每種類型都被定義為一個常量:LUA_TNIL、LUA_TBOOLEAN 、LUA_TNUMBER 、LUA_TSTRING 、LUA_TTABLE 、LUA_TFUNCTION、LUA_TUSERDATA 以及LUA_TTHREAD。
int lua_is... (lua_State *L, int index);
lua_isnumber 和lua_isstring
d.轉換棧中指定位置的元素數據類型的C函數
int lua_toboolean (lua_State *L, int index);
double lua_tonumber (lua_State *L, int index);
const char * lua_tostring (lua_State *L, int index);
size_t lua_strlen (lua_State *L, int index);
其他棧操作函數
int lua_gettop (lua_State *L);返回堆棧中的元素個數,它也是棧頂元素的索引。
void lua_settop (lua_State *L, int index);設置棧頂(也就是堆棧中的元素個數)為一個指定的值。如果開始的棧頂高于新的棧頂,頂部的值被丟棄。否則,為了得到指定的大小這個函數壓入相應個數的空值(nil)到棧上。lua_settop(L,0)清空堆棧
void lua_pushvalue (lua_State *L, int index);壓入堆棧上指定索引的一個拷貝到棧頂
void lua_remove (lua_State *L, int index);移除指定索引位置的元素,并將其上面所有的元素下移來填補這個位置的空白
void lua_insert (lua_State *L, int index);移動棧頂元素到指定索引的位置,并將這個索引位置上面的元素全部上移至棧頂被移動留下的空隔
void lua_replace (lua_State *L, int index);從棧頂彈出元素值并將其設置到指定索引位置,沒有任何移動操作(使用時,先要將替代的數據壓入棧頂)
C API 的錯誤處理
Lua 利用C 的setjmp 技巧構造了一個類似異常處理的機制。
C環境引用lua的普通全局變量
--lua配置文件 data.lua
if getenv("DISPLAY") == ":0.0" then
??? width = 300; height = 300
else
??? width = 200; height = 200
end
#c文件加載lua運行后,lua環境中的變量
main.c
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
void load (char *filename, int *width, int *height) {
??? lua_State *L = lua_open();
??? luaopen_base(L);
??? luaopen_io(L);
??? luaopen_string(L);
??? luaopen_math(L);
??? if (luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
?????? error(L, "cannot run configuration file: %s",lua_tostring(L, -1));
??? lua_getglobal(L, "width");
??? lua_getglobal(L, "height");
??? if (!lua_isnumber(L, -2))
?????? error(L, "`width' should be a number\n");
??? if (!lua_isnumber(L, -1))
?????? error(L, "`height' should be a number\n");
??? *width = (int)lua_tonumber(L, -2);
??? *height = (int)lua_tonumber(L, -1);
??? lua_close(L);
}
C環境引用lua的表
--lua中的配置文件data.lua
background = {r=0.30, g=0.10, b=0}
#c文件加載lua運行后,lua環境中的變量
main.c
#define MAX_COLOR 255
main(){
...
lua_getglobal(L, "background");
if (!lua_istable(L, -1))
??? error(L, "`background' is not a valid color table");
red = getfield("r");
green = getfield("g");
blue = getfield("b");
...
}
int getfield (const char *key) {
int result;
lua_pushstring(L, key);
lua_gettable(L, -2);
if (!lua_isnumber(L, -1))
?? error(L, "invalid component in background color");
result = (int)lua_tonumber(L, -1) * MAX_COLOR;
lua_pop(L, 1); /* remove number */
return result;
}#可以將lua中的表里面的值傳遞到c中來,也可以在C語言中為lua創建一個新表。
C語言向lua中生產一個表
void setfield (const char *index, int value) {
lua_pushstring(L, index);
lua_pushnumber(L, (double)value/MAX_COLOR);
lua_settable(L, -3);
}
void setcolor (struct ColorTable *ct) {
lua_newtable(L); /* creates a table */
setfield("r", ct->red); /* table.r = ct->r */
setfield("g", ct->green); /* table.g = ct->g */
setfield("b", ct->blue); /* table.b = ct->b */
lua_setglobal(ct->name); /* 'name' = table */
}
c調用setcolor()后在lua中生成后的表
WHITE = {r=1, g=1, b=1}
RED = {r=1, g=0, b=0}
C環境引用lua的函數
--lua文件中的函數data.lua
function f (x, y)
? return (x^2 * math.sin(y))/(1 - x)
end
#c文件加載lua運行后,調用lua中的函數
double f (double x, double y) {
? double z;
?? /* push functions and arguments */
? lua_getglobal(L, "f"); /* function to be called */
? lua_pushnumber(L, x); /* push 1st argument */
? lua_pushnumber(L, y); /* push 2nd argument */
? /* do the call (2 arguments, 1 result) */
? if(lua_pcall(L, 2, 1, 0) != 0)
???? error(L, "error running function `f': %s",
? lua_tostring(L, -1));
? /* retrieve result */
? if (!lua_isnumber(L, -1))
???? error(L, "function `f' must return a number");
? z = lua_tonumber(L, -1);
? lua_pop(L, 1); /* pop returned value */
? return z;
}#可以編寫一個通用的函數調用接口
本文轉自 a_liujin 51CTO博客,原文鏈接:http://blog.51cto.com/a1liujin/1705525,如需轉載請自行聯系原作者
總結
- 上一篇: SQL Server 2012入门T-S
- 下一篇: 如何安全的存储用户密码?(中)代码篇