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

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

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

В любом языке программирования необходима обработка ошибок. Типы ошибок включают:

  • Ошибки в грамматике

  • Ошибка выполнения

Ошибки в грамматике

Ошибки в грамматике обычно возникают из-за неправильного использования компонентов программы (например, операторов, выражений). Пример:

-- test.lua файл
a == 2

Результат выполнения кода выше будет:

lua: test.lua:2: '==' ожидается около

Как вы видите, в предыдущем примере出现了 синтаксическая ошибка, отличия между "=" и "==" очевидны. "=" это оператор присваивания, а "==" это сравнение.

Другой пример:

for a=1,10
   print(a)
end

Выполнение вышеуказанного кода приведет к следующим ошибкам:

lua: test2.lua:2: 'do' ожидается около 'print'

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

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

Ошибка выполнения

Ошибка выполнения заключается в том, что программа может正常运行, но будет выводиться информация об ошибке. Например, из-за неправильного ввода параметров программа выдает ошибку при выполнении:

function add(a,b)
   возврат a+b
end
add(10)

Когда мы компилируем и запускаем следующий код, компиляция может быть успешной, но при выполнении могут возникнуть следующие ошибки:

lua: test2.lua:2: попытка выполнения арифметического действия с локальной переменной 'b' (значением nil)
stack traceback:
    test2.lua:2: в функции 'add'
    test2.lua:5: в main блоке
    [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 не является числом")
   возврат a+b
end
add(10)

Выполнение вышеуказанного кода приведет к следующим ошибкам:

lua: test.lua:3: b не является числом
stack traceback:
    [C]: в функции 'assert'
    test.lua:3: в local 'add'
    test.lua:6: в главном блоке
    [C]: в ?

Пример: если 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, ...)
-- Нет ошибок
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 '1' else print '0' end
0

pcall вызывается в "защитном режиме" для первого параметра, поэтому pcall может улавливать любые ошибки, возникающие в процессе выполнения функции.

Обычно, когда возникает ошибка, мы хотим получить больше информации о调试, а не только положение ошибки. Но при возвращении pcall часть содержимого стека вызовов уже уничтожена.

Lua предоставляет функцию xpcall, которая принимает второй параметр - функцию обработки ошибок. При возникновении ошибки Lua вызывает функцию обработки ошибок до расширения стека (unwind), что позволяет использовать библиотеку 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: в функции <stdin:1>
[C]: в функции 'error'
stdin:1: в функции <stdin:1>
[C]: в функции 'xpcall'
stdin:1: в головном блоке
[C]: в ?
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: попытка выполнить арифметическое операция с глобальной 'н' (пустое значение)
false