这章之前有章讲环境的,经常用到的概念和遇到的坑在前面或多或少都有涉及,所以跳过了。这章简写为debug
- 追溯错误发生步骤,Rstudio自带功能/traceback()函数可实现
> f <- function(a) g(a)
> g <- function(b) h(b)
> h <- function(c) i(c)
> i <- function(d) "a" + d
> f(10)
#会报存在非数值参数的错误,点击Traceback,出现如下图的结果:从下往上看,错误发生在f()到i()逐渐调用,直至错误发生。点击Rerun with debug,可以运行到错误代码行
#如果没有使用Rstudio, traceback()函数照样可以实现
> traceback()
4: i(c) at #1
3: h(b) at #1
2: g(a) at #1
1: f(10)

- 函数抛出意想不到的警告时,可以使用options(warn =2),讲警告转换为错误,然后使用常规调试工具解决
> f <- function(a){
+ if (a ==0){
+ warning("a can not equal to zero")
+ }
+ a
+ }
> f(0)
[1] 0
Warning message:
In f(0) : a can not equal to zero
> options(warn =2)
> f(0)

- 消息转错误
> message2error <- function(code) {
+ withCallingHandlers(code, message = function(e) stop(e))
+ }
>
> f <- function() g()
> g <- function() message("Hi!")
> g()
Hi!
> message2error(g())
Error in message("Hi!") : Hi!
> traceback()
10: stop(e) at #2
9: (function (e)
stop(e))(list(message = "Hi!\n", call = message("Hi!")))
8: signalCondition(cond)
7: doWithOneRestart(return(expr), restart)
6: withOneRestart(expr, restarts[[1L]])
5: withRestarts({
signalCondition(cond)
defaultHandler(cond)
}, muffleMessage = function() NULL)
4: message("Hi!") at #1
3: g()
2: withCallingHandlers(code, message = function(e) stop(e)) at #2
1: message2error(g())
- 条件处理
# try()
> f1 <- function(x) {
+ log(x)
+ 10
+ }
> f1("x")
Error in log(x) : 数学函数中用了非数值参数
#遇到错误,抛出错误,然后并不继续执行
#try()可以忽略错误,继续执行下面的代码
> f2 <- function(x) {
+ try(log(x))
+ 10
+ }
> f2("a")
Error in log(x) : 数学函数中用了非数值参数
[1] 10
#可以加上参数silent = TRUE来进制Error信息抛出
> f2 <- function(x) {
+ try(log(x),silent = TRUE)
+ 10
+ }
> f2("a")
[1] 10
#try()中放置长代码,需要用{}
> try({
+ a <- 1
+ b <- "x"
+ a + b
+ })
Error in a + b : 二进列运算符中有非数值参数
- 捕获try()的输出
success <- try(1 + 2)
failure <- try("a" + "b")
#> Error in "a" + "b" : non-numeric argument to binary operator
class(success)
#> [1] "numeric"
class(failure)
#> [1] "try-error"
- 列表中多个元素使用同一个函数进行处理时,try()就很有用
elements <- list(1:10, c(-1, 10), c(TRUE, FALSE), letters)
results <- lapply(elements, log)
#> Warning in FUN(X[[i]], ...): NaNs produced
#> Error in FUN(X[[i]], ...): non-numeric argument to mathematical function
results <- lapply(elements, function(x) try(log(x)))
#> Warning in log(x): NaNs produced
#> Error in log(x) : non-numeric argument to mathematical function
- 自定义可以检测try-error类的函数,帮助找到错误位置
is.error <- function(x) inherits(x, "try-error")
succeeded <- !vapply(results, is.error, logical(1))
# look at successful results
str(results[succeeded])
#> List of 3
#> $ : num [1:10] 0 0.693 1.099 1.386 1.609 ...
#> $ : num [1:2] NaN 2.3
#> $ : num [1:2] 0 -Inf
# look at inputs that failed
str(elements[!succeeded])
#> List of 1
#> $ : chr [1:26] "a" "b" "c" "d" ...
- try()可以在表达式失败时,使用默认值,记得在try()外面赋值就行
default <- NULL
try(default <- read.csv("possibly-bad-input.csv"), silent = TRUE)
- tryCatch()将条件映射到处理程序(handler),只能捕获特定类型的错误,而不是依赖于错误字符串的比较
show_condition <- function(code) {
tryCatch(code,
error = function(c) "error",
warning = function(c) "warning",
message = function(c) "message"
)
}
show_condition(stop("!"))
#> [1] "error"
show_condition(warning("?!"))
#> [1] "warning"
show_condition(message("?"))
#> [1] "message"
# If no condition is captured, tryCatch returns the
# value of the input
show_condition(10)
#> [1] 10
- tryCatch()实现try()
try2 <- function(code, silent = FALSE) {
tryCatch(code, error = function(c) {
msg <- conditionMessage(c)
if (!silent) message(c)
invisible(structure(msg, class = "try-error"))
})
}
try2(1)
#> [1] 1
try2(stop("Hi"))
#> Error in doTryCatch(return(expr), name, parentenv, handler): Hi
try2(stop("Hi"), silent = TRUE)
- 修改存储在错误条件对象中的消息,让错误信息更详细
read.csv2 <- function(file, ...) {
tryCatch(read.csv(file, ...), error = function(c) {
c$message <- paste0(c$message, " (in ", file, ")")
stop(c)
})
}
read.csv("code/dummy.csv")
#> Error in file(file, "rt"): cannot open the connection
read.csv2("code/dummy.csv")
#> Error in file(file, "rt"): cannot open the connection (in code/dummy.csv)
- WithCallingHandlers(), 哦对,多说一点,这种函数命名的方法称为驼峰法(单词首字母大写);tryCatch()的替代函数,但有些许区别。前者中的处理程序是在产生条件的调用的上下文中被调用的,而后者中的处理程序是在tryCatch()的上下文被调用的。大多数情况下不去使用WithCallingHandlers()
f <- function() g()
g <- function() h()
h <- function() stop("!")
tryCatch(f(), error = function(e) print(sys.calls()))
# [[1]] tryCatch(f(), error = function(e) print(sys.calls()))
# [[2]] tryCatchList(expr, classes, parentenv, handlers)
# [[3]] tryCatchOne(expr, names, parentenv, handlers[[1L]])
# [[4]] value[[3L]](cond)
withCallingHandlers(f(), error = function(e) print(sys.calls()))
# [[1]] withCallingHandlers(f(),
# error = function(e) print(sys.calls()))
# [[2]] f()
# [[3]] g()
# [[4]] h()
# [[5]] stop("!")
# [[6]] .handleSimpleError(
# function (e) print(sys.calls()), "!", quote(h()))
# [[7]] h(simpleError(msg, call))
- 防御性编程,这个我不懂,不写了
网友评论