歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Lua基礎 編譯、運行、錯誤處理

盡管Lua是一門解析型的語言,但是在運行前也會被編譯成某個中間狀態。一門解析型的語言需要編譯,這聽起來有點不合常理。但是,實際上,解析型語言的與眾不同,不是說它不需要編譯,而是說它把編譯作為其運行時的一部分,因此,它就可以執行各種來自外部的代碼(例如網上的)。也許因為Lua中存在的如dofile 這樣的函數,才使Lua可以被稱為一門解析型語言。

1. 編譯

之前我們介紹了dofile 來執行代碼塊,但是dofile 只是一個輔助函數。這裡介紹一下loadfile 函數,它會從一個file中加載語句塊,但是不運行;而是僅僅編譯並作為一個函數返回。loadfile 不會像dofile 那樣在運行時直接報錯退出,而是返回錯誤碼,這樣我們就可以根據錯誤碼做相應的處理。我們可以像下面這樣定義dofile,這也可以看出dofile 和loadfile 的區別

function dofile (filename)
    local f = assert(loadfile(filename))
    return f()
end

注意,assert 可以使loadfile 發生錯誤時,報錯退出。

dofile 在處理有些簡單的任務時,使用起來比較方便,只需要一次調用,它會完成所有的操作(編譯,運行啥的)。但是,loadfile更加靈活。發生錯誤的時候,loadfile 會返回nil + 'err_msg',我們可以根據實際情況對錯誤做出相應的處理。除此之外,如果想要運行一個file多次,可以先調用一次loadfile,然後調用loadfile 返回的結果多次,就可以了。這比調用幾次dofile 開銷要小很多,因為loadfile 只會執行一次編譯,而dofile 每次都用都要編譯。

loadstring 跟loadfile 差不多,區別是從一個string中加載代碼塊,而不是從file中。例如:

f = loadstring("i = i + 1")

f 是loadstring 的返回值,應該是function類型, 調用的時候,會執行i = i + 1 :

i = 0
f(); print(i) --> 1
f(); print(i) --> 2

loadstring 函數功能非常強大,但是運行起來,開銷也不小,並且有時會導致產生一些莫名其妙的代碼。因此,在用loadstring 之前,先考慮下有沒有更簡單的辦法。
 
下面這行代碼,不太好看,但是很方便。(不鼓勵這種調用方法)

loadstring(s)()

如果有語法錯誤,loadstring 會返回nil + 類似‘attempt to call a nil value’這樣的err_msg。如果想獲取更詳細的err_msg,那就需要用assert :

assert(loadstring(s))()

下面這樣的使用方式(對一個字面值string使用loadstring),沒什麼意思,

f = loadstring("i = i + 1")

粗略的等價於:

但是,也不是完全相同,且繼續往下看。第二種方式的代碼運行起來更快,因為它只需要編譯一次,而loadstring 每次都需要編譯。下面我們來看看,上面兩段代碼到底有什麼不同,如下示例:

i = 32
local i = 0
f = loadstring("i = i + 1; print(i)")
g = function () i = i + 1; print(i) end
f() --> 33
g() --> 1

g 函數處理的事局部變量i , 而f 函數處理的是全局變量i ,loadstring 總是在全局環境中進行編譯。

loadstring 最典型的用途是:運行外來代碼,例如網絡上的,別人的。。。注意,loadsting 只能load語句,不能load表達式, 如果你想算一個表達式的值,那麼前面要加上一個return 來返回給定表達式的值。下面是一個示例幫助理解:

print "enter your expression:"
local l = io.read()
local func = assert(loadstring("return " .. l))
print("the value of your expression is " .. func())

看一下運行情況:(注意第一個為什麼報錯了,想想什麼才叫表達式)

loadstring 返回的就是一個普通的函數,可以多次調用:

print "enter function to be plotted (with variable 'x'):"
local l = io.read()
local f = assert(loadstring("return " .. l))
for i=1,20 do
    x = i -- global 'x' (to be visible from the chunk)
    print(string.rep("*", f()))
end

(string.rep 函數復制一個string給定的次數),下面是運行結果:

如果我們在深究一下,其實不管loadstring 也好,loadfile 也好,Lua中最基礎的函數是load 。loadfile 從一個file中加載代碼塊,loadstring 從一個string中加載代碼塊,而load 調用一個reader函數來獲取代碼塊,這個reader 函數分塊返回代碼塊,load 調用它,直到它返回nil 。我們很少使用load 函數;通常只有在代碼塊不是位於一個file中,但是又太大了,不適合放到內存中(如果適合放到內存中,那就可以用loadstring 了)的時候,才會用load 。

Copyright © Linux教程網 All Rights Reserved