0Pricing
R Academy · Lekcja

withCallingHandlers() i restarty

Używaj withCallingHandlers() do obsługi warunków w sposób nielokalny.

withCallingHandlers() i restarty to bezpłatna lekcja R Academy na CoddyKit. To lekcja 3 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 R Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs R Academy zawiera 4 lekcji w sumie.

tryCatch a withCallingHandlers

Najważniejsza różnica polega na tym, że tryCatch() ustanawia nielokalne wyjście — po przechwyceniu warunku sterowanie opuszcza wyrażenie i już do niego nie wraca. withCallingHandlers() zachowuje stos wywołań i może wznowić wykonywanie po obsłużeniu warunku.

# 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 zachowuje wykonywanie

W przypadku withCallingHandlers() procedura obsługi jest wykonywana, ale działanie jest kontynuowane po zgłoszeniu warunku (chyba że sama procedura obsługi zgłosi błąd lub wywoła restart). Stos wywołań nie jest rozwijany.

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')
})

Restart muffleWarning

Wywołanie invokeRestart('muffleWarning') wewnątrz procedury obsługi ostrzeżenia zapobiega wyświetleniu ostrzeżenia przez domyślną procedurę obsługi R. Bez tego po wykonaniu Państwa procedury obsługi R nadal wyświetliłby ostrzeżenie za pomocą domyślnego mechanizmu.

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

Restart muffleMessage

Podobnie invokeRestart('muffleMessage') wewnątrz procedury obsługi komunikatu wycisza komunikat po przetworzeniu go przez niestandardową procedurę obsługi. Na tym mechanizmie opiera się suppressMessages().

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

Rejestrowanie ostrzeżeń bez zatrzymywania działania

Praktyczne zastosowanie withCallingHandlers() polega na zbieraniu ostrzeżeń do wektora dziennika i jednoczesnym pozwoleniu kodowi na dokończenie działania. tryCatch() zatrzymałoby się przy pierwszym ostrzeżeniu, natomiast withCallingHandlers() zbiera je wszystkie.

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

Koncepcja invokeRestart()

Restarty to wstępnie zdefiniowane strategie odzyskiwania, które może udostępnić kod zgłaszający warunek. invokeRestart(name) wybiera jedną z tych strategii. Wbudowane restarty obejmują 'muffleWarning' i 'muffleMessage'; własne można definiować za pomocą 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')
)

Łączenie withCallingHandlers i tryCatch

Można je zagnieżdżać: należy użyć zewnętrznego withCallingHandlers() do rejestrowania lub zliczania warunków, a wewnętrznego tryCatch() do zapewnienia wartości zastępczej. Zewnętrzna procedura obsługi widzi warunek jako pierwsza.

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

Niestandardowe klasy warunków

Niestandardowe klasy warunków można tworzyć, wywołując structure() dla listy z klasą c('myError', 'error', 'condition'). Procedury obsługi dopasowują się według klasy, dlatego niestandardowe klasy pozwalają przechwytywać konkretne typy błędów bez przechwytywania wszystkich błędów.

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

Kiedy używać withCallingHandlers

Należy używać withCallingHandlers(), gdy chce się obserwować lub rejestrować warunki bez zatrzymywania działania. tryCatch() należy stosować, gdy chce się obsłużyć warunek i zwrócić alternatywną wartość. Narzędzia te rozwiązują różne problemy.

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

Łańcuch zgłaszania warunku

Po zgłoszeniu warunku R przechodzi w górę stosu wywołań w poszukiwaniu procedur obsługi. Procedury obsługi withCallingHandlers() działają w kontekście dynamicznym (ze zachowanym stosem wywołań). Procedury obsługi tryCatch() działają po rozwinięciu stosu — pierwotny kontekst jest już niedostępny.

# 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()

Implementacja suppressWarnings()

suppressWarnings(expr) jest zasadniczo równoważne withCallingHandlers(expr, warning = function(w) invokeRestart('muffleWarning')). Zrozumienie tego mechanizmu pozwala tworzyć własne warianty wyciszające tylko określone typy ostrzeżeń.

# 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')
)

Szybkie sprawdzenie

Na czym polega główna różnica między withCallingHandlers() a tryCatch()?

Restarty: najważniejsze informacje

Najważniejsze informacje dotyczące withCallingHandlers i restartów:

  • withCallingHandlers() = lokalna procedura obsługi, zachowany stos wywołań, możliwość kontynuowania działania
  • tryCatch() = nielokalne wyjście, rozwinięty stos, możliwość zwrócenia alternatywnej wartości
  • invokeRestart('muffleWarning') wycisza domyślne wyświetlanie ostrzeżenia
  • invokeRestart('muffleMessage') wycisza domyślne wyświetlanie komunikatu
  • withCallingHandlers() służy do zbierania lub rejestrowania wszystkich warunków bez zatrzymywania działania
  • Niestandardowe klasy warunków umożliwiają wybiórcze przechwytywanie konkretnych typów błędów
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')

Często zadawane pytania

Czy lekcja „withCallingHandlers() i restarty” jest bezpłatna?

Tak — pełny tekst „withCallingHandlers() i restarty” 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 R Academy, przejdź na CoddyKit PRO. Kurs R Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „withCallingHandlers() i restarty”?

Używaj withCallingHandlers() do obsługi warunków w sposób nielokalny. Ćwiczysz R 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ąć R Academy?

Nie wymagamy żadnego doświadczenia. R 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 3 z 4.

Ile czasu zajmuje lekcja „withCallingHandlers() i restarty”?

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 R Academy?

Tak. Każda lekcja R 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. Błędy, ostrzeżenia i komunikaty w R
  2. tryCatch() do obsługi błędów
  3. withCallingHandlers() i restarty
  4. Pisanie odpornych funkcji za pomocą stop() i warning()
← Powrót do R Academy