【问题标题】:Use tryCatch skip to next value of loop upon error?错误时使用 tryCatch 跳到循环的下一个值?
【发布时间】:2011-12-26 23:49:29
【问题描述】:

我已经阅读了一些关于 tryCatch 和 cuzzins 的其他 SO 问题,以及文档:

但我还是不明白。

我正在运行一个循环,如果出现以下几种错误中的任何一种,我想跳到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 不知道呢?

【问题讨论】:

    标签: r error-handling exception-handling try-catch


    【解决方案1】:

    使用tryCatch 的关键是意识到它返回一个对象。如果tryCatch 中存在错误,则该对象将继承自类error。您可以使用函数inherit 测试类继承。

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

    编辑:

    参数error = function(e) e是什么意思?这让我感到困惑,我认为文档中没有很好地解释它。发生的情况是,此参数捕获源自您是tryCatching 的表达式的任何错误消息。如果捕获到错误,则将其作为tryCatch 的值返回。在帮助文档中,这被描述为calling handlererror=function(e) 中的参数 e 是源自您的代码的错误消息。


    我来自程序编程的老派,使用next 是一件坏事。所以我会像这样重写你的代码。 (请注意,我删除了tryCatch 中的next 语句。):

    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 记录在 ?for` 中。

    如果您想使用它而不是将主要工作例程放在 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
    

    【讨论】:

    • 感谢您的回答。我最初像您推荐的那样避免了next,但是当我想到可能会被捕获的错误越来越多时,代码变成了一堆括号:与在Excel单元格中“编程”一系列条件一样糟糕或更糟糕.
    • 当我运行?for 时,下一行是+。 (请求更多输入)
    • @Andrie,如果函数为空,写error=function(e) 有什么意义?这应该是其他东西的简写吗?
    • 我的错误。应该是error=function(e) e。这将返回错误消息。我还在答案中添加了对这种机制的解释。
    • 我很好奇为什么您更愿意避免使用“下一个” - 无论是旧学校还是新学校,这通常被认为是 IME 的良好做法。与“goto 被认为有害”的东西非常不同,后者确实非常有害。但是循环控制运算符可以极大地简化代码并消除哨点变量,这些变量往往会出现令人讨厌的边缘情况。正如@LaoTzu 指出的那样,您可以节省很多括号和大括号。
    【解决方案2】:

    我发现其他答案非常令人困惑。对于任何想在发生错误时简单地跳到下一个循环迭代的人来说,这是一个非常简单的实现

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

    【讨论】:

    • 终于!这么多复杂的解释。但是在这里,您简化了整个过程,从而为社区做出了巨大的贡献。这应该是最受好评的答案!
    • 对于那些对&lt;&lt;- 感到困惑的人,这不是错字。 &lt;&lt;- 是超赋值运算符。它在封闭环境中进行分配。也就是说,在这种情况下,来自 for 循环的skip_to_next 被分配了一个来自tryCatch() 的值。查看更多here
    • 您的答案也有点令人困惑,因为您在循环结束时调用next,这在您的情况下是完全没有必要的:-) 另外,不需要&lt;&lt;-,因为您可以从错误处理程序返回值,它将成为tryCatch的返回值。
    【解决方案3】:
    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】:

      我看到的唯一真正详细的解释可以在这里找到: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))
      

      【讨论】:

        【解决方案5】:

        breaking out of for loop when running a function inside a for loop in R 明确指出我遗漏的一件事是:

        • next 在函数内部不起作用。
        • 您需要从函数内部(在我的情况下为 tryCatch)向外部发送一些信号或标志(例如,Voldemort = TRUE)。
        • (这就像在本地私有函数中修改全局公共变量)
        • 然后在函数之外,检查标志是否被挥动(Voldemort == TRUE)。如果是这样,请在函数外调用 breaknext

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-20
        • 2019-10-29
        • 1970-01-01
        • 2021-06-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-31
        相关资源
        最近更新 更多