Use tryCatch skip to next value of loop upon error?

后端 未结 5 1330
滥情空心
滥情空心 2020-11-29 15:51

I\'ve read a few other SO questions about tryCatch and cuzzins, as well as the documentation:

  • Exception handling in R
  • catching an error a
相关标签:
5条回答
  • 2020-11-29 16:09
    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 = ""))
    
    }
    
    0 讨论(0)
  • 2020-11-29 16:10

    I found other answers very confusing. Here is an extremely simple implementation for anyone who wants to simply skip to the next loop iteration in the event of an error

    for (i in 1:10) {
    
      skip_to_next <- FALSE
    
      # Note that print(b) fails since b doesn't exist
    
      tryCatch(print(b), error = function(e) { skip_to_next <<- TRUE})
    
      if(skip_to_next) { next }     
    }
    
    0 讨论(0)
  • 2020-11-29 16:10

    One thing I was missing, which breaking out of for loop when running a function inside a for loop in R makes clear, is this:

    • next doesn't work inside a function.
    • You need to send some signal or flag (e.g., Voldemort = TRUE) from inside your function (in my case tryCatch) to the outside.
    • (this is like modifying a global, public variable inside a local, private function)
    • Then outside the function, you check to see if the flag was waved (does Voldemort == TRUE). If so you call break or next outside the function.
    0 讨论(0)
  • 2020-11-29 16:14

    The key to using tryCatch is realising that it returns an object. If there was an error inside the tryCatch then this object will inherit from class error. You can test for class inheritance with the function inherit.

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

    Edit:

    What is the meaning of the argument error = function(e) e? This baffled me, and I don't think it's well explained in the documentation. What happens is that this argument catches any error messages that originate in the expression that you are tryCatching. If an error is caught, it gets returned as the value of tryCatch. In the help documentation this is described as a calling handler. The argument e inside error=function(e) is the error message originating in your code.


    I come from the old school of procedural programming where using next was a bad thing. So I would rewrite your code something like this. (Note that I removed the next statement inside the 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
    

    The function next is documented inside ?for`.

    If you want to use that instead of having your main working routine inside an if, your code should look something like this:

    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
    
    0 讨论(0)
  • 2020-11-29 16:15

    The only really detailed explanation I have seen can be found here: http://mazamascience.com/WorkingWithData/?p=912

    Here is a code clip from that blog post showing how tryCatch works

    #!/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))
    
    0 讨论(0)
提交回复
热议问题