Utilisez tryCatch passer à la valeur suivante de boucle en cas d'erreur?

j'ai lu quelques autres questions sur tryCatch et cuzzins, ainsi que la documentation:

mais je ne comprends toujours pas.

j'exécute une boucle et je veux passer à next si l'un des quelques types d'erreurs se produisent:

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

(soit dit en passant, il n'y a pas de documentation pour next que je peux trouver)

quand j'exécute ceci, R honks:

Error in value[[3L]](cond) : no loop for break/next, jumping to top level

Qu'est-ce qui me manque ici? Le tryCatch est clairement dans la boucle for , alors pourquoi R ne le sait pas?

43
demandé sur smci 2011-11-11 16:20:57

4 réponses

la clé pour utiliser tryCatch est de réaliser qu'il retourne un objet. S'il y avait une erreur à l'intérieur du tryCatch alors cet objet héritera de la classe error . Vous pouvez tester l'héritage de classe avec la fonction inherit .

x <- tryCatch(stop("Error"), error = function(e) e)
class(x)
"simpleError" "error"       "condition"  

Edit:

que signifie l'argument error = function(e) e ? Cela m'a déconcerté, et je ne pense pas que ce soit bien expliqué dans la documentation. Ce qui se passe est que cet argument saisit tous les messages d'erreur qui proviennent de l'expression que vous êtes tryCatch ing. Si une erreur est détectée, elle est renvoyée avec la valeur tryCatch . Dans la documentation d'aide, ceci est décrit comme un calling handler . L'argument e à l'intérieur de error=function(e) est le message d'erreur provenant de votre code.


je viens de l'ancienne école de la programmation procédurale où l'utilisation next était une mauvaise chose. Donc je réécrirais ton code quelque chose comme ça. (Notez que j'ai supprimé la mention next à l'intérieur de la mention 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

la fonction next est documentée à l'intérieur de ? pour".

si vous voulez utiliser cela au lieu d'avoir votre routine de travail principale à l'intérieur d'un if , votre code devrait ressembler à quelque chose comme ceci:

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
66
répondu Andrie 2011-11-12 07:48:55

la seule explication vraiment détaillée que j'ai vu se trouve ici: http://mazamascience.com/WorkingWithData/?p=912

voici un extrait de code de ce billet de blog montrant comment fonctionne 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
répondu mmann1123 2012-03-29 18:18:49
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 = ""))

}
4
répondu ewittry 2015-07-23 00:55:18

une chose que je manquais, qui rupture de boucle for lors de l'exécution d'une fonction à l'intérieur d'une boucle for Dans R fait clair, est ceci:

  • next ne fonctionne pas à l'intérieur d'une fonction.
  • vous devez envoyer un signal ou un drapeau (par exemple, Voldemort = TRUE ) de l'intérieur de votre fonction (dans mon cas tryCatch ) à l'extérieur.
  • (c'est comme modifier une variable publique globale à l'intérieur d'un privé, local de la fonction)
  • puis en dehors de la fonction, vous vérifiez si le drapeau a été agité (fait Voldemort == TRUE ). Si c'est le cas, vous appelez break ou next en dehors de la fonction.
3
répondu isomorphismes 2017-05-23 12:18:17