0Pricing
Lua Academy · Lekcja

Wywołania chronione za pomocą pcall

Proszę bezpiecznie przechwytywać błędy za pomocą pcall i interpretować zwracane wartości.

Wywołania chronione za pomocą pcall to bezpłatna lekcja Lua Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Lua Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Lua Academy zawiera 4 lekcji w sumie.

Podstawy pcall

pcall(f, ...) wywołuje funkcję f z argumentami ... w trybie chronionym. Jeśli f zakończy się pomyślnie, pcall zwraca true, a następnie wszystkie wartości zwrócone przez funkcję. Jeśli f zgłosi błąd, pcall zwraca false, a następnie komunikat błędu. W obu przypadkach program działa dalej.

local function risky(x)
  if x < 0 then error("negative input: " .. x) end
  return math.sqrt(x)
end

local ok, result = pcall(risky, 9)
print(ok, result)    -- true  3.0

ok, result = pcall(risky, -1)
print(ok, result)    -- false  ...: negative input: -1

Przechwytywanie konkretnych błędów

Po użyciu pcall należy sprawdzić typ wartości błędu, aby różne rodzaje błędów obsługiwać w różny sposób. Błędy będące tabelami zawierają dane strukturalne, a błędy tekstowe — komunikat. Należy zawsze obsługiwać oba przypadki.

local function op(errType)
  if errType == "table" then
    error({code=42, msg="structured error"})
  else
    error("plain string error")
  end
end

local ok, err = pcall(op, "table")
if not ok then
  if type(err) == "table" then
    print("Code:", err.code, "Msg:", err.msg)
  else
    print("String error:", err)
  end
end

Wiele wartości zwracanych po sukcesie

Po pomyślnym wykonaniu pcall zwraca wszystkie wartości zwrócone przez chronioną funkcję, poprzedzone początkową wartością true. Należy przypisać je do wielu zmiennych.

local function compute(a, b)
  return a + b, a * b, a - b
end

local ok, sum, product, diff = pcall(compute, 6, 4)
if ok then
  print("sum:", sum, "product:", product, "diff:", diff)
  -- sum: 10  product: 24  diff: 2
end

Zagnieżdżanie pcall

Wywołania pcall można zagnieżdżać. Każde pcall tworzy niezależny chroniony zakres. Błąd w wewnętrznym pcall zostanie przechwycony przez wewnętrzne pcall, a nie przez zewnętrzne. Umożliwia to implementowanie strategii awaryjnych.

local function tryPrimary()
  error("primary failed")
end

local function tryFallback()
  return "fallback result"
end

local ok, result = pcall(tryPrimary)
if not ok then
  print("Primary failed:", result)
  ok, result = pcall(tryFallback)
end

if ok then print("Got:", result) end  -- fallback result

pcall z metodami

Aby wywołać metodę (składnia z dwukropkiem) za pomocą pcall, należy przekazać funkcję i obiekt jako pierwszy argument. Można użyć pcall(obj.method, obj, args...) albo opakować wywołanie w domknięcie.

local obj = {
  x = 10,
  compute = function(self, n)
    if n == 0 then error("zero divisor") end
    return self.x / n
  end
}

-- Pass method + self explicitly
local ok, v = pcall(obj.compute, obj, 2)
print(ok, v)   -- true  5.0

-- Or use a closure
ok, v = pcall(function() return obj:compute(0) end)
print(ok, v)   -- false  ...zero divisor

pcall dla bezpieczeństwa operacji wejścia-wyjścia

Operacje wejścia-wyjścia należy opakować w pcall, aby przechwytywać nieoczekiwane błędy systemu operacyjnego. Należy zwracać spójną parę wynik/błąd, aby kod wywołujący mógł poprawnie obsługiwać niepowodzenia.

local function safeRead(path)
  local ok, result = pcall(function()
    local f = assert(io.open(path, "r"))
    local content = f:read("a")
    f:close()
    return content
  end)
  if ok then return result
  else return nil, result
  end
end

local data, err = safeRead("config.txt")
if data then print("Read", #data, "bytes")
else print("Error:", err)
end

Wzorzec ponawiania z pcall

Należy ponawiać zawodne operacje (żądanie sieciowe, zapis pliku) maksymalnie N razy, używając pcall do przechwytywania błędów. W rzeczywistym kodzie między próbami należy wstrzymać wykonanie (lub użyć coroutine).

local function retry(fn, maxAttempts)
  local attempts = 0
  while attempts < maxAttempts do
    attempts = attempts + 1
    local ok, result = pcall(fn)
    if ok then
      print("Succeeded on attempt", attempts)
      return result
    end
    print("Attempt", attempts, "failed:", result)
  end
  error("all " .. maxAttempts .. " attempts failed")
end

local n = 0
retry(function()
  n = n + 1
  if n < 3 then error("not ready") end
  return "done"
end, 5)

Zapisywanie wyników pcall w tabeli

Gdy pcall jest używane w pętli, wyniki należy przechowywać w tabeli do późniejszej analizy. Jest to przydatne podczas operacji wsadowych, gdy chcą Państwo przetworzyć wszystkie elementy i zebrać błędy zamiast zatrzymywać się przy pierwszym niepowodzeniu.

local jobs = {10, -5, 25, 0, 16}
local results = {}

for _, n in ipairs(jobs) do
  local ok, v = pcall(function()
    if n < 0 then error("negative") end
    return math.sqrt(n)
  end)
  results[#results+1] = {input=n, ok=ok, value=v}
end

for _, r in ipairs(results) do
  if r.ok then
    print(r.input, "->", string.format("%.3f", r.value))
  else
    print(r.input, "-> ERROR:", r.value)
  end
end

pcall a xpcall

pcall przechwytuje błąd, ale udostępnia tylko jego wartość. xpcall pozwala przekazać funkcję obsługi komunikatu, która działa, gdy stos jest jeszcze nienaruszony, dzięki czemu można uzyskać ślady stosu. Należy wybrać xpcall, gdy potrzebne są ślady stosu.

-- pcall: simple, no traceback
local ok1, err1 = pcall(function()
  error("simple error")
end)
print(err1)   -- only the error message

-- xpcall: with traceback handler
local ok2, err2 = xpcall(
  function() error("traced error") end,
  function(e) return debug.traceback(e, 2) end
)
print(err2)   -- full stack trace

Konwencja wartości zwracanych przez pcall

pcall należy stosować jako podstawę spójnego API: po pomyślnym wykonaniu zawsze zwracać value, a po niepowodzeniu nil, errorMessage. Funkcje należy budować w ten sposób, aby kod wywołujący zawsze wiedział, czego się spodziewać.

local function loadJSON(path)
  local ok, result = pcall(function()
    local f = assert(io.open(path, "r"))
    local text = f:read("a")
    f:close()
    -- Fake JSON parse for demo
    return {data = text, path = path}
  end)
  if ok then return result
  else return nil, result
  end
end

local data, err = loadJSON("data.json")
if data then print("Loaded:", data.path)
else print("Failed:", err)
end

Szybkie sprawdzenie

Co zwraca pcall, gdy chroniona funkcja zakończy się pomyślnie?

Podsumowanie: pcall

Podsumowanie:

  • pcall(f, ...) → true, results... albo false, err
  • Należy sprawdzić pierwszą wartość zwracaną, aby określić powodzenie lub niepowodzenie
  • Po wartości true w przypadku sukcesu występuje wiele wartości zwracanych
  • Zagnieżdżone pcall: każde niezależnie przechwytuje własne błędy
  • Wzorzec ponawiania: pętla z pcall dla zawodnych operacji
  • Należy użyć xpcall, gdy potrzebne są ślady stosu

Często zadawane pytania

Czy lekcja „Wywołania chronione za pomocą pcall” jest bezpłatna?

Tak — pełny tekst „Wywołania chronione za pomocą pcall” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Lua Academy, przejdź na CoddyKit PRO. Kurs Lua Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Wywołania chronione za pomocą pcall”?

Proszę bezpiecznie przechwytywać błędy za pomocą pcall i interpretować zwracane wartości. Ćwiczysz Lua Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Lua Academy?

Nie wymagamy żadnego doświadczenia. Lua Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Wywołania chronione za pomocą pcall”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Lua Academy?

Tak. Każda lekcja Lua Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Funkcja error()
  2. Wywołania chronione za pomocą pcall
  3. xpcall i programy obsługi komunikatów
  4. Strukturalne obiekty błędów
← Powrót do Lua Academy