0Pricing
Lua Academy · درس

الاستدعاءات المحمية باستخدام pcall

التقط الأخطاء بأمان باستخدام pcall وفسّر القيم المرجعة

الاستدعاءات المحمية باستخدام pcall درس مجاني في Lua Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Lua Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Lua Academy 4 دروس في المجموع.

أساسيات pcall

يستدعي pcall(f, ...) الدالة f بالوسائط ... في وضع محمي. إذا نجحت f، يعيد pcall القيمة true متبوعةً بجميع قيم الإرجاع. وإذا أصدرت f خطأً، يعيد pcall القيمة false متبوعةً برسالة الخطأ. يستمر البرنامج في كلتا الحالتين.

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

التقاط أخطاء محددة

تحقق من نوع قيمة الخطأ بعد pcall لمعالجة أنواع الأخطاء المختلفة بطرق مختلفة. تحتوي أخطاء الجداول على بيانات منظّمة، بينما تحتوي الأخطاء النصية على رسالة. احرص دائمًا على معالجة كلتا الحالتين.

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

قيم إرجاع متعددة عند النجاح

عند النجاح، يعيد pcall جميع قيم الإرجاع الخاصة بالدالة المحمية بعد القيمة true الأولية. التقط هذه القيم باستخدام متغيرات متعددة.

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

تداخل pcall

يمكن تداخل استدعاءات pcall. ينشئ كل pcall نطاقًا محميًا مستقلًا. يلتقط pcall الداخلي الخطأ الواقع داخله، وليس pcall الخارجي. يتيح لك ذلك تنفيذ استراتيجيات بديلة.

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 مع الأساليب

لاستدعاء أسلوب (باستخدام صيغة النقطتين) عبر pcall، مرّر الدالة والكائن بوصفهما الوسيطين الأولين. pcall(obj.method, obj, args...) أو غلّف الاستدعاء في إغلاق.

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 لأمان عمليات الإدخال والإخراج

غلّف عمليات الإدخال والإخراج في pcall لالتقاط أخطاء نظام التشغيل غير المتوقعة. أعد زوجًا متسقًا من النتيجة والخطأ حتى يتمكن المستدعون من معالجة حالات الفشل بسلاسة.

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

نمط إعادة المحاولة باستخدام pcall

أعد محاولة عملية غير مستقرة (مثل طلب شبكة أو كتابة ملف) حتى N مرات، باستخدام pcall لالتقاط الأخطاء. أضف فترة انتظار بين المحاولات في الشيفرة الفعلية (أو استخدم coroutines).

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)

تخزين نتائج pcall في جدول

عند استخدام pcall داخل حلقة، خزّن النتائج في جدول لتحليلها لاحقًا. يفيد ذلك في العمليات الدفعية التي تريد فيها معالجة جميع العناصر وجمع الأخطاء بدلًا من التوقف عند أول فشل.

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 مقارنةً بـ xpcall

يلتقط pcall الخطأ، لكنه يمنحك قيمة الخطأ فقط. يتيح لك xpcall توفير دالة لمعالجة الرسالة تعمل بينما يكون المكدس سليمًا، مما يتيح إنشاء تتبعات للمكدس. اختر xpcall عندما تحتاج إلى تتبعات الأخطاء.

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

اتفاقية إرجاع pcall

استخدم pcall أساسًا لواجهة برمجية متسقة: أعد دائمًا value عند النجاح، أو nil, errorMessage عند الفشل. ابنِ دوالك على هذا النحو حتى يعرف المستدعون دائمًا ما يمكن توقعه.

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

تحقق سريع

ماذا يعيد pcall عندما تنجح الدالة المحمية؟

مراجعة: pcall

الملخص:

  • pcall(f, ...) → true, results... أو false, err
  • تحقق من قيمة الإرجاع الأولى لتحديد النجاح أو الفشل
  • تأتي قيم الإرجاع المتعددة بعد true عند النجاح
  • pcall المتداخل: يلتقط كل استدعاء أخطاءه باستقلالية
  • نمط إعادة المحاولة: استخدم حلقة مع pcall للعمليات غير المستقرة
  • استخدم xpcall عندما تحتاج إلى تتبعات المكدس

الأسئلة الشائعة

هل درس «الاستدعاءات المحمية باستخدام pcall» مجاني؟

نعم — نص درس «الاستدعاءات المحمية باستخدام pcall» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Lua Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Lua Academy 4 دروس في المجموع.

ماذا ستتعلم في «الاستدعاءات المحمية باستخدام pcall»؟

التقط الأخطاء بأمان باستخدام pcall وفسّر القيم المرجعة تتمرن على Lua Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Lua Academy؟

لا تُشترط خبرة سابقة. Lua Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «الاستدعاءات المحمية باستخدام pcall»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Lua Academy هذا؟

نعم. كل درس في Lua Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. الدالة error()
  2. الاستدعاءات المحمية باستخدام pcall
  3. ‏xpcall ومعالجات الرسائل
  4. كائنات الأخطاء المهيكلة
← العودة إلى Lua Academy