Calling handlers provide a way of 'touching' a condition on the way through, maybe logging an error to a file before signalling the user in an interactive session.
Calling handlers can be used to 'muffle' warnings, messages, or errors if the calling handler doesn't actually return. You can make a calling handler not return using restarts -- surround the code that you'd like to continue executing in a call to withRestarts()
, and invoke the restart in the handler:
f2 <- function() {
cat("before tryCatch
")
withCallingHandlers({
withRestarts({
stop("this is an error!")
}, muffleStop=function() {
message("'stop' muffled")
})
},
error = function(cond) {
print(cond$message)
invokeRestart("muffleStop")
}
)
cat("after tryCatch
")
}
It's more usual that the restarts are established in one chunk of code (like in the built-in function warning
) and invoked in a completely independent chunk of code (like the built-in function suppressWarnings
:
> warning
function (..., call. = TRUE, immediate. = FALSE, noBreaks. = FALSE,
domain = NULL)
{
##
## ...
##
withRestarts({
.Internal(.signalCondition(cond, message, call))
.Internal(.dfltWarn(message, call))
}, muffleWarning = function() NULL)
##
## ...
##
}
<bytecode: 0x51a4730>
<environment: namespace:base>
> suppressWarnings
function (expr)
{
ops <- options(warn = -1)
on.exit(options(ops))
withCallingHandlers(expr,
warning = function(w) invokeRestart("muffleWarning"))
}
<bytecode: 0x35c2a60>
<environment: namespace:base>
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…