Обработка ошибок в Lua

Обработка ошибок во время выполнения программы необходима. Непредвиденные ошибки могут возникать при файловых операциях, передаче данных и вызовах веб-служб. Если информацию об ошибке не обрабатывать должным образом, это может привести к утечке информации, сбою программы и другим проблемам.

Любой язык программирования требует обработки ошибок. Типы ошибок включают:

  • Синтаксические ошибки
  • Ошибки времени выполнения

Синтаксические ошибки

Синтаксические ошибки обычно вызваны неправильным использованием компонентов программы (таких как операторы и выражения). Простой пример выглядит следующим образом:

-- 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'

Синтаксические ошибки проще, чем ошибки времени выполнения программы. Ошибки времени выполнения не могут указать конкретную ошибку, но синтаксические ошибки можно быстро устранить. Например, в приведенном выше примере нам просто нужно добавить "do" под оператором for:

Пример

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 is not a number")
   assert(type(b) == "number", "b is not a number")
   return a+b
end
добавьте(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])

Функция: завершает текущую выполняющуюся функцию и возвращает содержимое message в качестве сообщения об ошибке (функция error никогда не возвращает управление)

Обычно error добавляет некоторую информацию о местоположении ошибки в начало сообщения.

Параметр Level указывает, откуда получить местоположение ошибки:

  • Level=1 [по умолчанию]: позиция вызова error (файл + номер строки)
  • Level=2: указывает, какая функция вызвала функцию, которая вызывает error
  • Level=0: не добавлять информацию о местоположении ошибки

pcall и xpcall, debug

Для обработки ошибок в Lua можно использовать функцию pcall (защищённый вызов), чтобы обернуть код, который нужно выполнить.

pcall принимает функцию и параметры, которые нужно ей передать, и выполняет её. Результаты выполнения: с ошибкой, без ошибки; возвращаемое значение: true или false, errorinfo.

Формат синтаксиса следующий:

if pcall(function_name, ….) then
-- 没有错误
else
-- 一些错误
end

Простой пример:

Пример

> =pcall(function(i) print(i) end, 33)
33
истина
   
> =pcall(function(i) print(i) error('error..') end, 33)
33
false        stdin:1: error..
> function f() return false,2 end
> if f() then print '1' else 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: attempt to perform arithmetic on global 'n' (a nil value)
false
Другие расширения