Skip to content

Instantly share code, notes, and snippets.

@blogdron
Forked from Fingercomp/pcall-load.md
Created January 5, 2024 03:05
Show Gist options
  • Save blogdron/3a67441d087450a0da8ab0263e9f6bb8 to your computer and use it in GitHub Desktop.
Save blogdron/3a67441d087450a0da8ab0263e9f6bb8 to your computer and use it in GitHub Desktop.
О `pcall` и `load` в Lua

Познакомимся с load. Эта функция берёт первым аргументом строку и компилирует её.

local str = "Тест!"
print(load(str))
--> nil [string "Тест!"]:1: unexpected symbol near '<\208>'

Код выше вернёт странные идеограммы, но если присмотреться, то становится заметно, что именно там происходит.

Если строка, которую мы дали, содержит невалидный Lua код (не луа-код совсем или с синтаксическими ошибками), то load возвращает nil и описание ошибки.

local str = "Тест!"
local chunk, err = load(str)

print(err)
--> [string "Тест!"]:1: unexpected symbol near '<\208>'

Если же load видит, что мы дали валидный код на Lua, то он его, как уже сказал, компилирует. И преобразует в функцию, которую load вернёт.

local str = [[print("Hello, world!")]]
local chunk, err = load(str)
chunk()
--> Hello, world!

Да, как видно, если мы вызовем эту функцию, то будет исполнен переданный лоаду код. Круто.

Что будет, если в коде возникнет ошибка?

local str = [[error("Ошибка!")]]
local chunk, err = load(str)
chunk()
print("Всё ок?")

Упс. На третьей строке у нас вся программа остановится и выбросит ошибку.

Такая же штука будет, если в str мы засунем что-то вроде [[print("удав" + "собака")]].

К счастью, мы можем и эту ошибку отловить. Для чего теперь уже используется функция pcall. Она принимает как аргумент функцию и параметры к ней. После чего вызывает переданную функцию и, если в коде возникает ошибка, возвращает false и описание ошибки.

local str = [[print("кот" + "собака")]]
local chunk, err = load(str)
local result, err = pcall(chunk)
print(err)
--> [string "print("кот" + "собака")"]:1: attempt to perform arithmetic on a string value

Если же ошибок не будет, pcall вернёт true и всё то, что в коде передано через return.

local str = [[print("кот + собака")]]
local chunk, err = load(str)
local result, err = pcall(chunk)
print(result, err)
--> true nil

Отлично. Осталось теперь всё это оформить. Для чего мы создадим отдельную функцию.

local function runCode(code)
  local chunk, err = load(code)

  if not chunk then
    -- load вернул ошибку
    return false, err
  end
  
  local success, returnValue = pcall(chunk)
  
  if not success then
    -- pcall поймал ошибку
    return false, returnValue
  end
  
  -- всё хорошо, ошибок нет
  return true, returnValue
end

print(runCode([[print(rip irc)]]))
--> false [string "print(rip irc)"]:1: ')' expected near 'irc'

print(runCode([[print("rip" + "irc")]]))
--> false [string "print("rip" + "irc")"]:1: attempt to perform arithmetic on a string value

print(runCode([[print("rip" .. "irc")]]))
--> ripirc
--> true nil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment