English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Lua 오류 처리

程序运行中错误处理是必要的,在我们进行文件操作,数据转移及web service 调用过程中都会出现不可预期的错误。如果不注重错误信息的处理,就会造成信息泄露,程序无法运行等情况。

任何程序语言中,都需要错误处理。错误类型有:

  • 语法错误

  • 运行错误

语法错误

语法错误通常是由于对程序的组件(如运算符、表达式)使用不当引起的。一个简单的示例如下:

-- test.lua 文件
a == 2

以上代码执行结果为:

lua: test.lua:2: syntax error near '=='

正如你所看到的,以上出现了语法错误,一个 "=" 号跟两个 "=" 号是有区别的。一个 "=" 是赋值表达式两个 "=" 是比较运算。

另外一个示例:

for a= 1,10
   print(a)
end

위 프로그램을 실행하면 다음과 같은 오류가 발생합니다:

lua: test2.lua:2: 'do' expected near 'print'

语法错误比程序运行错误更简单,运行错误无法定位具体错误,而语法错误我们可以很快的解决,如以上示例我们只要在for语句下添加 do 即可:

for a= 1,10
do
   print(a)
end

运行错误

运行错误是程序可以正常执行,但是会输出报错信息。如下示例由于参数输入错误,程序执行时报错:

function add(a,b)
   return a+b
end
add(10)

当我们编译运行以下代码时,编译是可以成功的,但在运行的时候会产生如下错误:

lua: test2.lua:2: attempt to perform arithmetic on local 'b' (a nil value)
stack traceback:
    test2.lua:2: in function 'add'
    test2.lua:5: in main chunk
    [C]: ?

lua 里调用函数时,即使实参列表和形参列表不一致也能成功调用,多余的参数会被舍弃,缺少的参数会被补为 nil。

以上报错信息是由于参数 b 被补为 nil 后,nil 参与了 + 运算。

假如 add 函数内不是 "return a+b" 而是 "print(a,b)" 的话,结果会变成 "10 nil" 不会报错。

错误处理

我们可以使用两个函数:assert 和 error 来处理错误。示例如下:

local function add(a,b)
   assert(type(a) == "number", "a 不是一个数字")
   assert(type(b) == "number", "b 不是一个数字")
   return a+b
end
add(10)

위 프로그램을 실행하면 다음과 같은 오류가 발생합니다:

lua: test.lua:3: b는 숫자가 아닙니다.
stack traceback:
    [C]: in function 'assert'
    test.lua:3: in local 'add'
    test.lua:6: in main chunk
    [C]: in ?

예제에서 assert는 첫 번째 매개변수를 체크하면, 문제가 없다면 assert는 어떤 작업도 수행하지 않습니다. 문제가 있으면, assert는 두 번째 매개변수를 오류 메시지로 표출합니다.

error 함수

문법 형식:

error (message[, level])

기능: 실행 중인 함수를 종료하고 메시지 내용을 오류 정보로 반환합니다. (error 함수는 결코 반환하지 않습니다.)

보통 error는 메시지 헤더에 오류 위치 정보를 추가합니다.

Level 매개변수는 오류 위치를 얻을지를 지정

  • Level=1[기본] : 호출된 error 위치(파일+행 번호)

  • Level=2: error 함수를 호출한 함수를 지정

  • Level=0: 오류 위치 정보 추가하지 않음

pcall과 xpcall, debug

Lua에서 오류를 처리하려면 pcall (protected call) 함수를 사용하여 필요한 코드를 포장할 수 있습니다.

pcall은 함수를 받아들이고, 그에 대한 매개변수를 전달하여 실행하며, 실행 결과는 오류가 있는지 없는지, 반환 값 true 또는 false, errorinfo입니다.

문법 형식:

if pcall(function_name, ...) then
-- 오류 없음
else
-- 일부 오류
end

간단한 예제:

> =pcall(function(i) print(i) end, 33)
33
true
   
> =pcall(function(i) print(i) error('error..') end, 33)
33
false stdin:1: error..

이곳에서 반환 값을 대한 논리 판단에 유의하세요:

> function f() return false,2 end
> if f() then print '1else print '0' end
0

pcall은 "보호 모드"로 첫 번째 매개변수를 호출하므로, pcall은 함수 실행 중에 발생할 수 있는 모든 오류를 잡을 수 있습니다.

오류가 발생할 때, 오류가 발생한 위치보다 더 많은 디버깅 정보를 얻고 싶습니다. 하지만 pcall이 반환될 때, 호출 스택의 일부 내용이 파괴되었습니다.

Lua는 xpcall 함수를 제공하며, xpcall은 두 번째 매개변수인 오류 처리 함수를 받아들이며, 오류가 발생할 때 Lua가 호출 스택에서 회전하기 전에 오류 처리 함수를 호출하여, 이 함수에서 debug 라이브러리를 사용하여 오류에 대한 추가 정보를 얻을 수 있습니다.

debug 라이브러리는 두 가지 일반적인 오류 처리 함수를 제공합니다:

  • debug.debug:사용자가 오류 원인을 확인할 수 있는 Lua 터미널을 제공합니다

  • debug.traceback:호출 스택을 기반으로 확장된 오류 메시지를 구축합니다

>=xpcall(function(i) print(i) error('error..') end, function() print(debug.traceback()) end, 33)
33
stack traceback:
stdin:1: in function <stdin:1>
[C]: in function 'error'
stdin:1: in function <stdin:1>
[C]: in function 'xpcall'
stdin:1: in main chunk
[C]: in ?
false        nil

xpcall 사용 예제 2:

function myfunction ()
   n = n/nil
end
function myerrorhandler( err )
   print( "ERROR:", err )
end
status = xpcall( myfunction, myerrorhandler )
print( status)

위 프로그램을 실행하면 다음과 같은 오류가 발생합니다:

ERROR:    test2.lua:2: 객체에 수학적 연산을 시도하려고 했습니다.전역 변수 'n'는 nil 값입니다.
false