天天看點

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檔案,并在記憶體中儲存是以變量。可以以此方式加載函數庫。

(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

 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進行操作

可以使用"..."表示函數的可變參數清單,函數的可變參數放在"下标索引"表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

使用疊代器:

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)  

疊代器用于範性for:

for element in list_iter(t) do

print(element)

c.非全局函數(表的成員函數)

Lib = {}

Lib.foo = function (x,y) return x + y end

function Lib.foo (x,y)

return x + y

d.正确的尾部調用(尾部遞歸)

function f(x)

return g(x)

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()

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

#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}

#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)

#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,如需轉載請自行聯系原作者

繼續閱讀