我有一个通用函数来捕获我的包中logR::tryCatch2 定义的所有异常,定义如下:
tryCatch2 <- function(expr){
V=E=W=M=I=NULL
e.handler = function(e){
E <<- e
NULL
}
w.handler = function(w){
W <<- c(W, list(w))
invokeRestart("muffleWarning")
}
m.handler = function(m){
attributes(m$call) <- NULL
M <<- c(M, list(m))
}
i.handler = function(i){
I <<- i
NULL
}
V = suppressMessages(withCallingHandlers(
tryCatch(expr, error = e.handler, interrupt = i.handler),
warning = w.handler,
message = m.handler
))
list(value=V, error=E, warning=W, message=M, interrupt=I)
}
Run Code Online (Sandbox Code Playgroud)
正如您在最后一行中所看到的,它返回一个或多或少自我描述的列表.
它tryCatch2通过简单的方式对调用后延迟的异常做出真正的反应!is.null:
f = function(){ warning("warn1"); warning("warn2"); stop("err") }
r = tryCatch2(f())
if(!is.null(r$error)) cat("Error detected\n")
# Error detected
if(!is.null(r$warning)) cat("Warning detected, count", length(r$warning), "\n")
# Warning detected, count 2
Run Code Online (Sandbox Code Playgroud)
它按预期工作,我可以用自己的代码做出反应.但在某些情况下,我不想停止也被捕获的中断过程.目前,似乎我需要添加额外的参数来tryCatch2控制是否应该捕获中断.所以问题是关于invokeInterrupt我可以通过以下方式使用的一些功能:
g = function(){ Sys.sleep(60); f() }
r = tryCatch2(g())
# interrupt by pressing ctrl+c / stop while function is running!
if(!is.null(r$interrupt)) cat("HERE I would like to invoke interrupt\n")
# HERE I would like to invoke interrupt
Run Code Online (Sandbox Code Playgroud)
我认为如果R能够捕获一个,它也应该能够调用一个.
我该如何实现invokeInterrupt功能?
迟到的答案,但我发现rlang::interrupt可以引发“用户中断”:
Interrupt() 允许 R 代码模拟使用 Ctrl-C 发出信号的用户中断。目前无法创建自定义中断条件对象。
来源:?rlang::interrupt
它在内部调用 R API 函数,Rf_onintr该函数是该函数的别名onintr。
基本上 an interrupt“只是”这些类的特殊条件:
interruptand condition(参见R 源代码)。
如果您只想模拟中断来测试tryCatch(无需中断正在运行的 R 语句),只需通过以下方式抛出这些类的条件即可signalCondition:
interrupt_condition <- function() {
structure(list(), class = c("interrupt", "condition"))
}
tryCatch(signalCondition(interrupt_condition()),
interrupt = function(x) print("interrupt detected"))
# [1] "interrupt detected"
Run Code Online (Sandbox Code Playgroud)