1. 程式人生 > >Step By Step(Lua編譯執行與錯誤)

Step By Step(Lua編譯執行與錯誤)

    1. 編譯:
    Lua中提供了dofile函式,它是一種內建的操作,用於執行Lua程式碼塊。但實際上dofile只是一個輔助函式,loadfile才是真正的核心函式。相比於dofile,loadfile只是從指定的檔案中載入Lua程式碼塊,然後編譯這段程式碼塊,如果有編譯錯誤,就返回nil,同時給出錯誤資訊,但是在編譯成功後並不真正的執行這段程式碼塊。因此,我們可以將dofile實現為:

1 function dofile(filename)
2     local f = assert(loadfile(filename))
3     return f()
4 end

    這裡如果loadfile執行失敗,assert函式將直接引發一個錯誤。通過dofile的程式碼,我們還可以看出,如果打算多次執行一個檔案中的Lua程式碼塊,我們可以只執行loadfile一次,之後多次執行它返回的結果即可,這樣就可以節省多次編譯所帶來的開銷。這一點也是loadfile和dofile在效能上的區別。
    Lua中還提供了另外一種動態執行Lua程式碼的方式,即loadstring

函式。顧名思義,相比於loadfile,loadstring的程式碼源來自於其引數中的字串,如:
    f = loadstring("i = i + 1")
    此時f就變成了一個函式,每次呼叫時就執行"i = i + 1",如:

1 i = 0
2 f()  
3 print(i) --將輸出14 f()
5 print(i) --將輸出2

    loadstring確實是一個功能強大的函式,但是由此而換來的效能開銷也是我們不得不考慮的事情。所以對於很多常量字串如果仍然使用loadstring方式,那就沒有太大意義了,如上面的例子f = loadstring("i = i + 1"),因為我們完全可以通過f = function () i = i + 1 end的形式取而代之。而後者的執行效率要遠遠高於前者。畢竟後者只編譯一次,而前者則在每次呼叫loadstring時均被編譯。對於loadstring,我們還需要注意的是,該函式總是在全域性環境中編譯它的字串,因此它將無法檔案區域性變數,而是隻能訪問全域性變數,如:

1 i = 32
2 local i = 0
3 f = loadstring("i = i + 1; print(i)")
4 g = function() i = i + 1; print(i) end
5 f()   --f函式中的i為全域性變數i,因此輸出336 g()   --g函式中的i為區域性變數i,因此輸出1

    對於loadstring返回的函式,如果需要對一個表示式求值,則必須在其之前新增return,這樣才能構成一條語句,返回表示式的值,如:

1 i = 32
2 f = loadstring("i = i + 1; return i * 2")
3 print
(f()) --輸出664 print(f()) --輸出68。由於loadstring返回的就是正規的函式,因此可以被反覆呼叫。

    Lua將所有獨立的程式塊視為一個匿名函式的函式體,並且該匿名函式還具有可變長實參,因此在呼叫loadstring時,可以為其傳遞引數,如:

1 local i = 30
2 --下面的...表示變長實參,將值賦給區域性變數x。3 local f = assert(loadstring("local x = ...; return (x + 10)    * 2")) 
4 for i = 1, 20 do
5     print(string.rep("*",f(i)))
6 end


    2. C程式碼:
    上一小節介紹的是動態載入Lua程式碼,而事實上,Lua本身也支援動態載入C動態庫中的程式碼,要完成該操作,我們需要藉助於Lua內建的系統函式package.loadlib。該函式有兩個字串引數,分別是動態庫的全檔名和該庫包含的函式名稱,典型的呼叫程式碼如下:
    local path = "/usr/local/lib/test.so"
    local f = package.loadlib(path,"test_func")
    由於loadlib是非常底層的函式,因為在呼叫時必須提供完整的路徑名和函式名稱。

    3. 錯誤:
    Lua作為一種嵌入式指令碼語言,在發生錯誤時,不應該只是簡單的退出或崩潰。相反,一旦有錯誤發生,Lua就應該結束當前程式塊並返回到應用程式。
    在Lua中我們可以通過error()函式獲取錯誤訊息,如:
    print "enter a number:"
    n = io.read("*number")
    if not n then error("invalid input") end
    上面程式碼中的最後一行我們可以通過Lua提供的另外一個內建函式assert類輔助完成,如:
    print "enter a number:"
    n = assert(io.read("*number"),"invalid input")
    assert函式將檢查其第一個引數是否為true,如果是,則簡單的返回該引數,否則就引發一個錯誤。第二個引數是可選字串。
    對於所有的程式語言而言,錯誤處理都是一個非常重要的環節。在實際的開發中,沒有統一的指導原則,只能是在遇到問題後,經過縝密的分析在結合當時的應用場景,最後結合自己的經驗再給出錯誤的具體處理方式。在有些情況下,我們可以直接返回錯誤碼,而在另外一些情況下,則需要直接丟擲錯誤,讓開發者能夠快速定位導致錯誤的程式碼源。

    4. 錯誤處理與異常:
    Lua提供了錯誤處理函式pcall,該函式的第一個引數為需要“保護執行”的函式,如果該函式執行失敗,pcall將返回false及錯誤資訊,否則返回true和函式呼叫的返回值。見如下程式碼:

複製程式碼
 1 function foo()
 2     local a = 10
 3     print(a[2])
 4 end
 5 
 6 r, msg = pcall(foo)
 7 if r then
 8     print("This is ok.")
 9 else
10     print("This is error.")
11     print(msg)
12 end
13 --輸出結果為:14 --This is error.15 --d:/test.lua:3: attempt to index local 'a' (a number value)
複製程式碼

    我們也可以給pcall函式直接傳遞匿名函式,如:

複製程式碼
 1 r, msg = pcall(function() error({code = 121}) end)
 2 if r then
 3     print("This is ok.")
 4 else
 5     print("This is error.")
 6     print(msg.code)
 7 end
 8 --輸出結果為: 9 --This is error.10 --121
複製程式碼


    5. 錯誤訊息與追溯:
    通常在錯誤發生時,希望得到更多的除錯資訊,而不是隻有發生錯誤的位置。至少等追溯到發生錯誤時和函式呼叫情況,顯示一個完整的函式呼叫棧軌跡。要完成這一功能,我們需要使用Lua提供的另外一個內建函式xpcall。該函式除了接受一個需要被呼叫的函式之外,還接受第二個引數,即錯誤處理函式。當發生錯誤時,Lua會在呼叫棧展開前呼叫錯誤處理函式。這樣,我們就可以在這個函式中使用debug庫的debug.traceback函式,它會根據呼叫棧來構建一個擴充套件的錯誤訊息。如:

複製程式碼
 1 function errorFunc()
 2     local a = 20
 3     print(a[10])
 4 end
 5 
 6 function errorHandle()
 7     print(debug.traceback())
 8 end
 9 
10 if xpcall(errorFunc,errorHandle) then
11     print("This is OK.")
12 else
13     print("This is error.")
14 end
15 
16 --輸出結果為:17 --[[stack traceback:
18         d:/test.lua:7: in function <d:/test.lua:6>
19         d:/test.lua:3: in function <d:/test.lua:1>
20         [C]: in function 'xpcall'
21         d:/test.lua:10: in main chunk
22         [C]: ?
23 This is error.
24 --]]

相關推薦

Step By Step(Lua編譯執行錯誤)

    1. 編譯:     Lua中提供了dofile函式,它是一種內建的操作,用於執行Lua程式碼塊。但實際上dofile只是一個輔助函式,loadfile才是真正的核心函式。相比於dofile,loadfile只是從指定的檔案中載入Lua程式碼塊,然後編譯這段程式碼

(6)LUA程式設計-編譯執行錯誤(compile 、run & error)處理

1.編譯問題 ---------------------------- ---------------------------- 首先我們談一下編譯的問題,LUA的執行,是將原始碼轉換成中間程式碼的形式執行的。 說到這裡,也許會有不少人會問,LUA不是一種解釋型語言,沒錯!

Step By Step(Lua元表元方法)

 Lua中提供的元表是用於幫助Lua資料變數完成某些非預定義功能的個性化行為,如兩個table的相加。假設a和b都是table,通過元表可以定義如何計算表示式a+b。當Lua試圖將兩個table相加時,它會先檢查兩者之一是否有元表,然後檢查該元表中是否存在__add欄位,

Step By Step(Lua模組包)

    從Lua 5.1開始,我們可以使用require和module函式來獲取和建立Lua中的模組。從使用者的角度來看,一個模組就是一個程式庫,可以通過require來載入,之後便得到一個型別為table的全域性變數。此時的table就像名字空間一樣,可以訪問其中的函式

Step By Step(Lua目錄)

處理 叠代 類型 引用 持久化 系統 for 聲明 錯誤處理 Step By Step(Lua開篇)http://www.cnblogs.com/stephen-liu74/archive/2012/03/17/2403210.html一、簡介二、主要優勢三、應用場景Ste

VmWare 宿主主機通信 STEP BY STEP (適用於剛開始學習的人)

aid 並且 cap 應該 行程 最大的 mtu win7 bringing 基本原理 在虛擬機中有三種通信方式,例如以下圖所看到的 1. Bridged(橋接模式) 在橋接模式下,VMware虛擬出來的操作系統就像是局域網中的一獨立的主機

Step By Step(Lua調用C函數)

extern lua環境 class 數量 lsp 相同 虛擬 c語言代碼 cti 原文: http://www.cnblogs.com/stephen-liu74/archive/2012/07/23/2469902.html Lua可以調用C函數的能力將極大的提高Lu

Step By Step(Lua呼叫C函式)

Lua可以呼叫C函式的能力將極大的提高Lua的可擴充套件性和可用性。對於有些和作業系統相關的功能,或者是對效率要求較高的模組,我們完全可以通過C函式來實現,之後再通過Lua呼叫指定的C函式。對於那些可被Lua呼叫的C函式而言,其介面必須遵循Lua要求的形式,即typedef

Tensorflow基礎知識神經網路構建--step by step 入門TensorFlow(一)

Tensorflow基礎知識與神經網路構建–step by step 入門TensorFlow(一) 標籤: Tensorflow 我們將採用Jupyter notebook互動式程式設計的方式,通過一步步程式碼的講解,學習Tensorflow程式設計。

Ubuntu 下Bitcoin編譯,單步除錯環境搭建(step by step

為了不被時代拋棄,連一聲再見都不說。最近開始研究bitcoin,主要是對C++比較熟。學習一項新技術,為達到效果,根據個人經驗從下面三個方面入手: 1. 買一本介紹原理的書,系統的瞭解,為什麼?因為書是別人智慧的總結,是一個完整的系統知識,站在前人肩膀遠勝過網路碎片化知識。

學習mybatis-3 step by step 篇一

odi png environ factor 數據 不能 val 集成開發環境 start 一、搭建簡單mybatis-3環境(詳細的中文文檔) 集成開發環境:IDEA 項目:maven + mybatis-3 1、創建maven結構項目 含簡單,如下圖: 下一步後,填寫

Angular4 step by step.3

pen 分享 -1 edi sco lar ide mod code 1.Routes 路由模塊 1 import { NgModule } from [email protected]/* *//core‘; 2 import

[轉]RDL(C) Report Design Step by Step 3: Mail Label

設置 ted 運算 lec 標題 report 對數 win 信息管理 本文轉自:http://www.cnblogs.com/waxdoll/archive/2006/09/02/493350.html Crystal Report在報表向導中提供了三種向導類型給用戶

WPF Step By Step 系列 - 開篇

gpu 查看 這一 order 界面設計 基礎知識 http 對比 快速 WPF 系列包含的內容 WPF基礎知識介紹 WPF布局介紹 WPF控件介紹(包含第三方控件) WPF自定義模板 WPF依賴屬性、路由事件 WPF的MVVM編程 WPF開發框架Prism WPF開

Quartz.NET開源作業調度框架系列(一):快速入門step by step-轉

rand 隨機 axis 開發人員 c# returns .net開源 觸發 mis  Quartz.NET是一個被廣泛使用的開源作業調度框架 , 由於是用C#語言創建,可方便的用於winform和asp.net應用程序中。Quartz.NET提供了巨大的靈活性但又兼具

Building your Deep Neural Network: Step by Step

pan auto plot chan arr src computing zeros rect Welcome to your week 4 assignment (part 1 of 2)! You have previously trained a 2-layer N

Step By Step 搭建 MySql MHA 集群

ip add 環境 def text 初始化 下載 git 下載源碼 恢復 關於MHA ?? MHA(Master High Availability)是一款開源的mysql高可用程序,目前在mysql高可用方面是一個相對成熟的解決方案。MHA 搭建的前提是MySQL集群中

Struts2+Spring+Hibernate step by step 06 整合Hibernate

emp 2.3 是否 ssh整合 配置 pla sets 映射類 veh 註:該系列教程。部分內容來自王健老師編寫ssh整合開發教程 Hibernate是一款優秀的ORM(Object Relation Mapping-對

Sentinel 集群安裝 step by step

port evel 創建 安裝redis dev lis win mat 8K 一、 準備材料 服務器 IP address 操作系統 位數 Redis 版本 CNT06CAH05

WPF MVVM 架構 Step By Step(4)(添加bindings - 完全去掉後臺代碼)

發送 要去 idt leak 事情 right 規範 ron source 原文:WPF MVVM 架構 Step By Step(4)(添加bindings - 完全去掉後臺代碼)  之前的改進已經挺棒的,但是我們現在知道了後臺代碼的問題,那是否可能把後臺代碼全部去除呢?