iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 27
0
Software Development

30天 Lua重拾筆記系列 第 27

【30天Lua重拾筆記26】進階議題: 錯誤處理

作為一個寄宿型的嵌入式語言,Lua設計更傾向由宿主語言(通常是C)處理錯誤。
但是可以在保護模式下,執行函式,並檢查函式是否執行成功。
很像是Go語言。這就是Lua的錯誤處理基本方法。

錯誤處理

作為一個寄宿型的嵌入式語言,Lua設計更傾向由宿主語言(通常是C)處理錯誤。

num = 10
str = "string"

print('Hello, Lua')

result = num / str -- Error: attempt to div a 'number' with a 'string'

print('here will not show, because error hapend before')

一般來說,並不傾向於Lua處理最後,因為數字與字串相除,所引發的錯誤。這個錯誤會持續引發至宿主語言,由宿主語言進行錯誤處裡。

#include "lua.h"
#include "lauxlib.h"

#include<stdio.h>
#include<stdlib.h>

int main(int argc, char *argv[]){

    // new a lua VM
    lua_State *L = luaL_newstate();

    // open base lib
    luaopen_base(L);

    // dostring
    /*  執行Lua片段 */
    int lua_result = luaL_dostring(L,
                                   "num = 10\n"
                                   "str = 'string'\n"
                                   "print('Hello, Lua')\n"
                                   "result = num / str -- Error: attempt to div a 'number' with a 'string'\n"
                                   "print('here will not show, because error hapend before')\n"
                                   );

    /* 檢查是否執行成功 */
    if(lua_result == LUA_OK){
      printf("run lua success.\n");
    }else{
      /*  處理錯誤  */
      printf("error code: %d\n", lua_result);

      /*  檢查錯誤訊息  */
      if(lua_isstring(L, -1)){
        const char *msg = lua_tostring(L, -1);
        lua_pop(L, 1);
        /*  顯示錯誤訊訊息  */
        printf("Error Message: %s\n", msg);
      }
    }

    return 0;
}

Hello, Lua
error code: 1
Error Message: [string "num = 10..."]:4: attempt to perform arithmetic on a string value (global 'str')

恩...你可能看不太懂,但大致可以看到與上方相同的Lua程式片段,並大概能夠理解由宿主語言去處理錯誤即可。與C交互並不是今天的重點。

pcall/xpcall

與函數形語言裡的call不太一樣的,Lua的pcallxpcall另有用途。

pcallxpcall可以將特定函式於保護模式(protect mode)下執行。其p即是protect(保護)的意思。

下面程式直接於Lua執行,並不會顯示錯誤訊息。

function error_chunk()
  local num = 10
  local str = "string"

  print('Hello, Lua')

  local result = num / str -- Error: attempt to div a 'number' with a 'string'

  print('here will not show, because error hapend before')
end

pcall(error_chunk)

檢查錯誤

ok = pcall(error_chunk)
print(ok) -- Output: false

取得執行結果

除了第一個反還值是執行是否成功以外,其他反還值才是函數真正執行結果:

function div(a,b)
  return a/b
end

ok, c = pcall(div, 10, 2)

if ok then
  print(c) --> Output: 5.0
end

執行失敗是不會有返回值的,以下面例子得到的是錯誤訊息。

ok, c = pcall(div, 10, "str")

if not ok then
  print("Error Message: ")
  print(c)
end

xpcall 處理錯誤

xpcall()而外接受一個錯誤處理者。以下例來說,錯誤處理者會反還一個預設結果0.5

function errorHandle(msg)
  print("Error Message"..msg)
  return .5
end

ok, c = xpcall(div, errorHandle, 10, "str")

print("----------")
print(ok, c) -- false 0.5

引發錯誤

Lua有兩種錯誤類型errorwarn

warn

實際上warn()並不算是錯誤,他不會中止程式執行,只會顯示一些訊息。

warn("Message") -- Output: Lua warning: Message

開啟警告

上面你可能沒看到顯示的錯誤訊息,這是因為一開始警告顯示是關閉的。你可以透過warn("@on")開啟警告。

warn("@on")

關閉警告

可以透過warn("@off")關閉警告。

warn("@off")
warn "message" -- no output

@開頭是warn的控制符,他會忽略非法的控制,像是下面即使開始警告,也不會有訊息:

warn("@on")
warn "@message" -- no output

error

error()永遠不會返回。其函數原形為:

error (message [, level])

level基本上可以不用理會,而message通常是字串:

ok, msg = pcall(error, "Message")
print(ok, msg) -- false Message

不過也可以是其他類型:

ok, msg_obj = pcall(error, {message = "Message"})
print(ok, type(msg_obj)) -- false table
print(msg_obj.message) -- Message

這也是為什麼在C處理錯誤時,先檢查是否為字串。


上一篇
【30天Lua重拾筆記25】進階議題: 模組化
下一篇
【30天Lua重拾筆記27】進階議題: debug
系列文
30天 Lua重拾筆記36

1 則留言

0
lagagain
iT邦新手 3 級 ‧ 2020-10-10 06:28:57

本文也可以在個人網站上閱讀。

我要留言

立即登入留言