Использовать tryCatch для перехода к следующему значению цикла при ошибке?
Я прочитал несколько других SO вопросов о tryCatch
и cuzzins, а также документацию:
но я все еще не понимаю
Я запускаю цикл и хочу перейти к next
если произойдет какая-либо из нескольких ошибок:
for (i in 1:39487) {
# EXCEPTION HANDLING
this.could.go.wrong <- tryCatch(
attemptsomething(),
error=function(e) next
)
so.could.this <- tryCatch(
doesthisfail(),
error=function(e) next
)
catch.all.errors <- function() { this.could.go.wrong; so.could.this; }
catch.all.errors;
#REAL WORK
useful(i); fun(i); good(i);
} #end for
(кстати, документации для next
я не найду)
Когда я запускаю это, R
сигналит:
Error in value[[3L]](cond) : no loop for break/next, jumping to top level
Какой основной момент я здесь упускаю? tryCatch
явно находится внутри цикла for
, так почему R
не знает об этом?
Ответы
Ответ 1
Ключ к использованию tryCatch
заключается в том, что он возвращает объект. Если в tryCatch
была ошибка, то этот объект наследуется от класса error
. Вы можете проверить наследование класса с помощью функции inherit
.
x <- tryCatch(stop("Error"), error = function(e) e)
class(x)
"simpleError" "error" "condition"
Изменить:
В чем смысл аргумента error = function(e) e
? Это меня озадачило, и я не думаю, что это хорошо объяснено в документации. Случается, что этот аргумент ловит любые сообщения об ошибках, которые возникают в выражении, которое вы tryCatch
ing. Если ошибка поймана, она возвращается как значение tryCatch
. В справочной документации это описывается как calling handler
. Аргумент e
внутри error=function(e)
- это сообщение об ошибке, происходящее из вашего кода.
Я пришел из старой школы процедурного программирования, где использование next
было плохим. Поэтому я бы переписал код таким образом. (Обратите внимание, что я удалил оператор next
внутри tryCatch
.):
for (i in 1:39487) {
#ERROR HANDLING
possibleError <- tryCatch(
thing(),
error=function(e) e
)
if(!inherits(possibleError, "error")){
#REAL WORK
useful(i); fun(i); good(i);
}
} #end for
Функция next
задокументирована внутри ?
для`.
Если вы хотите использовать это вместо своей основной рабочей процедуры внутри if
, ваш код должен выглядеть примерно так:
for (i in 1:39487) {
#ERROR HANDLING
possibleError <- tryCatch(
thing(),
error=function(e) e
)
if(inherits(possibleError, "error")) next
#REAL WORK
useful(i); fun(i); good(i);
} #end for
Ответ 2
rm(list=ls())
for (i in -3:3) {
#ERROR HANDLING
possibleError <- tryCatch({
print(paste("Start Loop ", i ,sep=""))
if(i==0){
stop()
}
}
,
error=function(e) {
e
print(paste("Oops! --> Error in Loop ",i,sep = ""))
}
)
if(inherits(possibleError, "error")) next
print(paste(" End Loop ",i,sep = ""))
}
Ответ 3
Единственное подробное объяснение, которое я видел, можно найти здесь: http://mazamascience.com/WorkingWithData/?p=912
Вот фрагмент кода из этого сообщения в блоге, показывающий, как tryCatch работает
#!/usr/bin/env Rscript
# tryCatch.r -- experiments with tryCatch
# Get any arguments
arguments <- commandArgs(trailingOnly=TRUE)
a <- arguments[1]
# Define a division function that can issue warnings and errors
myDivide <- function(d, a) {
if (a == 'warning') {
return_value <- 'myDivide warning result'
warning("myDivide warning message")
} else if (a == 'error') {
return_value <- 'myDivide error result'
stop("myDivide error message")
} else {
return_value = d / as.numeric(a)
}
return(return_value)
}
# Evalute the desired series of expressions inside of tryCatch
result <- tryCatch({
b <- 2
c <- b^2
d <- c+2
if (a == 'suppress-warnings') {
e <- suppressWarnings(myDivide(d,a))
} else {
e <- myDivide(d,a) # 6/a
}
f <- e + 100
}, warning = function(war) {
# warning handler picks up where error was generated
print(paste("MY_WARNING: ",war))
b <- "changing 'b' inside the warning handler has no effect"
e <- myDivide(d,0.1) # =60
f <- e + 100
return(f)
}, error = function(err) {
# warning handler picks up where error was generated
print(paste("MY_ERROR: ",err))
b <- "changing 'b' inside the error handler has no effect"
e <- myDivide(d,0.01) # =600
f <- e + 100
return(f)
}, finally = {
print(paste("a =",a))
print(paste("b =",b))
print(paste("c =",c))
print(paste("d =",d))
# NOTE: Finally is evaluated in the context of of the inital
# NOTE: tryCatch block and 'e' will not exist if a warning
# NOTE: or error occurred.
#print(paste("e =",e))
}) # END tryCatch
print(paste("result =",result))
Ответ 4
Одна вещь, которую я отсутствовал, которая вырывается из цикла for при запуске функции внутри цикла for в R, делает это:
-
next
не работает внутри функции.
- Вам нужно отправить какой-либо сигнал или флаг (например,
Voldemort = TRUE
) из вашей функции (в моем случае tryCatch
) вовнутрь.
- (это похоже на изменение глобальной, общедоступной переменной внутри локальной частной функции)
- Затем вне функции вы проверяете, был ли флагом помахали (делает
Voldemort == TRUE
). Если это так, вы вызываете break
или next
вне функции.
Ответ 5
Я нашел другие ответы очень запутанными. Вот чрезвычайно простая реализация для тех, кто хочет просто перейти к следующей итерации цикла в случае ошибки
for (i in 1:10) {
tryCatch(print(b), error = function(e) { print("hi"); skip_to_next <<- TRUE})
if(skip_to_next) { next }
}