0Pricing
R Academy · درس

withCallingHandlers() وإعادات التشغيل

استخدم withCallingHandlers() للتعامل مع الشروط غير المحلية.

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

tryCatch مقابل withCallingHandlers

يكمن الفرق الأساسي في أن tryCatch() ينشئ خروجًا غير محلي؛ فعند التقاط شرط، ينتقل التحكم خارج التعبير ولا يعود إليه. أما withCallingHandlers() فيُبقي مكدس الاستدعاءات سليمًا، ويمكنه استئناف التنفيذ بعد المعالجة.

# tryCatch: execution does NOT continue after warning
tryCatch({
  warning('first')
  cat('This line is never reached\n')
}, warning = function(w) cat('tryCatch caught:', w$message, '\n'))

يحافظ withCallingHandlers على استمرار التنفيذ

مع withCallingHandlers()، يُنفَّذ المعالج، لكن يستمر التنفيذ بعد الإشارة إلى الشرط، ما لم يُلقِ المعالج نفسه خطأً أو يستدعي إعادة تشغيل. ولا يحدث تفكيك لمكدس الاستدعاءات.

withCallingHandlers({
  warning('first warning')
  cat('Execution continues here\n')
  warning('second warning')
  cat('And here too\n')
}, warning = function(w) {
  cat('Handler saw:', w$message, '\n')
  invokeRestart('muffleWarning')
})

إعادة تشغيل muffleWarning

يؤدي استدعاء invokeRestart('muffleWarning') داخل معالج التحذير إلى منع معالج R الافتراضي من طباعة التحذير. ومن دونه، ستطبع R التحذير عبر آليتها الافتراضية بعد انتهاء تنفيذ معالجكم.

# Without muffleWarning: warning still shows after handler
withCallingHandlers({
  warning('test')
}, warning = function(w) {
  cat('Handler ran\n')
  # no muffleWarning: default handler still fires
})

إعادة تشغيل muffleMessage

وبالمثل، يؤدي استدعاء invokeRestart('muffleMessage') داخل معالج الرسائل إلى إسكات الرسالة بعد أن يعالجها معالجكم المخصص. وهذه هي الآلية التي تقف وراء suppressMessages().

withCallingHandlers({
  message('Progress: 50%')
  message('Progress: 100%')
}, message = function(m) {
  cat('[LOG]', trimws(m$message), '\n')
  invokeRestart('muffleMessage')
})

تسجيل التحذيرات دون إيقاف التنفيذ

من الاستخدامات العملية لـ withCallingHandlers() جمع التحذيرات في متجه سجل مع السماح للكود بإكمال التنفيذ. إذ يتوقف tryCatch() عند أول تحذير، بينما يجمع withCallingHandlers() جميع التحذيرات.

warnings_log <- character(0)
result <- withCallingHandlers({
  x <- log(-1)
  y <- sqrt(-4)
  c(x, y)
}, warning = function(w) {
  warnings_log <<- c(warnings_log, w$message)
  invokeRestart('muffleWarning')
})
cat('Warnings logged:', length(warnings_log), '\n')
cat(warnings_log, sep = '\n')

مفهوم invokeRestart()

إعادات التشغيل هي استراتيجيات استرداد محددة مسبقًا يمكن للكود الذي يشير إلى الشرط توفيرها. يختار invokeRestart(name) إحدى هذه الاستراتيجيات. تتضمن إعادات التشغيل المضمنة 'muffleWarning' و'muffleMessage'، ويمكنكم تعريف إعادات تشغيل مخصصة باستخدام withRestarts().

# withRestarts() offers named recovery options
divide_safe <- function(x, y) {
  withRestarts(
    {
      if (y == 0) stop('division by zero')
      x / y
    },
    use_zero = function() 0,
    use_na   = function() NA
  )
}
# A handler can pick a restart
withCallingHandlers(
  divide_safe(10, 0),
  error = function(e) invokeRestart('use_zero')
)

دمج withCallingHandlers وtryCatch

يمكنكم تداخل الاثنين: استخدموا withCallingHandlers() خارجيًا لتسجيل الشروط أو عدّها، واستخدموا tryCatch() داخليًا لتوفير قيمة بديلة. ويرى المعالج الخارجي الشرط أولًا.

n_warnings <- 0L
result <- withCallingHandlers(
  tryCatch(log(-1), warning = function(w) -999),
  warning = function(w) {
    n_warnings <<- n_warnings + 1L
    cat('Logged warning #', n_warnings, '\n')
  }
)
cat('Result:', result, '\n')

فئات الشروط المخصصة

يمكنكم إنشاء فئات شروط مخصصة باستدعاء structure() على قائمة ذات الفئة c('myError', 'error', 'condition'). تطابق المعالجات الفئة، لذا تتيح لكم الفئات المخصصة التقاط أنواع محددة من الأخطاء دون التقاط جميع الأخطاء.

my_error <- function(msg, data = NULL) {
  structure(
    class = c('my_error', 'error', 'condition'),
    list(message = msg, data = data)
  )
}
tryCatch(
  stop(my_error('custom error', data = 42)),
  my_error = function(e) cat('Custom handler, data=', e$data, '\n'),
  error    = function(e) cat('Generic handler\n')
)

متى تستخدمون withCallingHandlers

استخدموا withCallingHandlers() عندما تريدون مراقبة الشروط أو تسجيلها دون إيقاف التنفيذ. واستخدموا tryCatch() عندما تريدون التعافي من شرط وإرجاع قيمة بديلة. فكل منهما يعالج مشكلة مختلفة.

# withCallingHandlers: observe all, continue
withCallingHandlers(
  for (x in c(4, -1, 9, -4)) cat(suppressWarnings(sqrt(x)), ''),
  warning = function(w) cat('[warn]', '')
)
cat('\n')

سلسلة إرسال الشروط

عند إرسال شرط، تصعد R عبر مكدس الاستدعاءات بحثًا عن معالجات. تعمل معالجات withCallingHandlers() في السياق الديناميكي مع بقاء مكدس الاستدعاءات سليمًا. أما معالجات tryCatch() فتعمل بعد تفكيك المكدس، ويكون السياق الأصلي قد زال.

# Demonstrate: withCallingHandlers handler can see full stack
f <- function() {
  withCallingHandlers(
    g(),
    warning = function(w) {
      cat('Caught in f, stack length:', sys.nframe(), '\n')
      invokeRestart('muffleWarning')
    }
  )
}
g <- function() warning('from g')
f()

آلية تنفيذ suppressWarnings()

إن suppressWarnings(expr) هي في الأساس withCallingHandlers(expr, warning = function(w) invokeRestart('muffleWarning')). ويسمح لكم فهم ذلك ببناء صيغكم الخاصة التي تمنع أنواعًا معينة من التحذيرات فقط.

# Suppress only NaN warnings, not others
suppress_nan_warn <- function(expr) {
  withCallingHandlers(expr, warning = function(w) {
    if (grepl('NaN', conditionMessage(w)))
      invokeRestart('muffleWarning')
  })
}
suppress_nan_warn(log(-1))   # NaN warning suppressed
tryCatch(
  suppress_nan_warn(warning('other issue')),
  warning = function(w) cat('Other warning kept:', w$message, '\n')
)

تحقق سريع

ما الفرق الأساسي بين withCallingHandlers() وtryCatch()؟

إعادات التشغيل: أهم النقاط

أهم النقاط حول withCallingHandlers وإعادات التشغيل:

  • withCallingHandlers() = معالج محلي، مكدس الاستدعاءات سليم، ويمكن استمرار التنفيذ
  • tryCatch() = خروج غير محلي، المكدس مفكك، ويمكن إرجاع قيمة بديلة
  • يمنع invokeRestart('muffleWarning') الطباعة الافتراضية للتحذير
  • يمنع invokeRestart('muffleMessage') الطباعة الافتراضية للرسالة
  • استخدموا withCallingHandlers() لجمع جميع الشروط أو تسجيلها دون إيقاف التنفيذ
  • تتيح فئات الشروط المخصصة التقاط أنواع محددة من الأخطاء بصورة انتقائية
log_vec <- character(0)
withCallingHandlers({
  message('start')
  warning('low memory')
  message('end')
}, message = function(m) {
  log_vec <<- c(log_vec, paste('MSG:', trimws(m$message)))
  invokeRestart('muffleMessage')
}, warning = function(w) {
  log_vec <<- c(log_vec, paste('WARN:', w$message))
  invokeRestart('muffleWarning')
})
cat(log_vec, sep = '\n')

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

هل درس «withCallingHandlers() وإعادات التشغيل» مجاني؟

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

ماذا ستتعلم في «withCallingHandlers() وإعادات التشغيل»؟

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

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

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

كم من الوقت يستغرق درس «withCallingHandlers() وإعادات التشغيل»؟

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

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

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

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

  1. الأخطاء والتحذيرات والرسائل في R
  2. tryCatch() لاسترداد الأخطاء
  3. withCallingHandlers() وإعادات التشغيل
  4. كتابة دوال متينة باستخدام stop() وwarning()
← العودة إلى R Academy