R语言设计oedipus()函数实现从父级或第n级祖先抛出错误的咨询
问题解答
核心结论
完全可以实现你要求的oedipus()函数,不需要修改父函数的原有代码,仅通过R原生的调用栈操作和环境求值功能即可实现。
基础版实现(仅从父级抛出错误)
核心利用evalq()函数将stop()表达式放到父函数的执行环境中运行,相当于stop()是直接在父函数内部调用,自然不会在错误信息和调用栈中暴露oedipus()的存在:
oedipus <- function() { # 在直接父级的执行环境中触发错误 evalq( stop("Ow, my eyes!"), envir = parent.frame(n = 1) ) } laius <- function() { oedipus() } # 测试效果 laius() #> Error in laius() : Ow, my eyes!
如果需要保留简化的调用栈,效果完全符合你的预期:
#> Error in laius() : Ow, my eyes! #> #> 2. stop("Ow, my eyes!") #> 1. laius()
进阶版实现(支持指定n级祖先抛出错误)
通过动态调整求值的环境层级,即可实现按参数n指定任意层级的祖先函数抛出错误,实现代码如下:
oedipus <- function(n) { # 校验n的合法范围,避免超出调用栈深度 max_legal_n <- sys.nframe() - 1 if (n < 0 || n > max_legal_n) { stop(sprintf("n必须在0~%d范围内", max_legal_n)) } # 在指定的n级祖先环境中执行错误抛出 evalq( stop("Ow, my eyes!"), envir = parent.frame(n = n + 1) ) } # 测试用嵌套函数 laius <- function(...) { oedipus(...) } labdacus <- function(...) { laius(...) } polydorus <- function(...) { labdacus(...) }
测试效果完全符合你的要求:
polydorus(0) #> Error in oedipus(...) : Ow, my eyes! polydorus(1) #> Error in laius(...) : Ow, my eyes! polydorus(2) #> Error in labdacus(...) : Ow, my eyes! polydorus(3) #> Error in polydorus(3) : Ow, my eyes!
关于你提到的实现思路说明
你提到的evalq()+on.exit()的方案也是可行的:可以在oedipus()中给父级函数注册on.exit(stop(...), add = TRUE)的退出钩子,父函数退出时就会触发错误,不过这种方式会等到父函数运行到结束时才抛出错误,而上述evalq()的方案是立即终止执行,更符合常规的错误抛出逻辑。
内容的提问来源于stack exchange,提问作者Greg
相关产品推荐
相关产品推荐

