0Pricing
R Academy · บทเรียน

withCallingHandlers() และการเริ่มทำงานใหม่

ใช้ withCallingHandlers() เพื่อจัดการเงื่อนไขจากบริบทที่ไม่ใช่เฉพาะที่

withCallingHandlers() และการเริ่มทำงานใหม่ เป็นบทเรียน R Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 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() ด้านในเพื่อจัดเตรียมค่า fallback ตัวจัดการด้านนอกจะเห็นเงื่อนไขก่อน

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() และการเริ่มทำงานใหม่” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส R Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “withCallingHandlers() และการเริ่มทำงานใหม่”

ใช้ withCallingHandlers() เพื่อจัดการเงื่อนไขจากบริบทที่ไม่ใช่เฉพาะที่ คุณปฏิบัติ R Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน R Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน R Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “withCallingHandlers() และการเริ่มทำงานใหม่” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน R Academy นี้ได้ไหม

ได้ บทเรียน R Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ข้อผิดพลาด คำเตือน และข้อความใน R
  2. tryCatch() สำหรับการกู้คืนจากข้อผิดพลาด
  3. withCallingHandlers() และการเริ่มทำงานใหม่
  4. การเขียนฟังก์ชันที่ทนทานด้วย stop() และ warning()
← กลับไปที่ R Academy