繁体   English   中英

如何在主功能环境中有一个固定的“锚”?

[英]how to have a fixed "anchor" to the main function environment?

在一个包中,我有一个 main 函数,它调用许多其他未导出的函数,到处都有很多条件检查。

当使用 tidyverse 错误处理时,例如使用很棒的{cli}包,您可以附加一个调用者环境来装饰函数。 文档可在此处获得。

这是一些示例代码:

main = function() f1()
f1 = function() f2()
f2 = function() cli::cli_abort("foobar", call=rlang::caller_env())
main()
#> Error in `f1()`:
#> ! foobar

reprex 包创建于 2022-07-03 (v2.0.1)

调用者不是f2()而是它的父f1() ,但错误仍然没有提供信息,因为最终用户也不知道内部f1()函数。

要将main()作为最终调用者,我可以编写call=rlang::caller_env(2) ,这不是很容易维护,或者将调用者作为参数传递给堆栈的每个函数,这需要一个沉重的重构。

有没有办法让一个全局变量充当对main()的引用,并且我可以在我的代码中的任何地方使用它?

我能想到的只有(hacky)选项:

1:一次继续向上 1 个父环境,直到到达R_GlobalEnv ,然后返回 1 步。

main = function() f1()
f1 = function() f2()

f2 = function() {
  for(depth in 1:10) if(identical(rlang::caller_env(depth), globalenv())) break
  if(depth == 10) depth = 1
  cli::cli_abort("foobar", call=rlang::caller_env(depth-1))
}
main()

2:自己创建某种标识符,您可以搜索

main = function() {
  marker = "hello!"
  f1()
}
f1 = function() f2()
f2 = function() {
  for(depth in 1:10) try( if( get('marker', envir = rlang::caller_env(depth)) == "hello!" ) break, silent = T)
  if(depth == 10) depth = 0
  cli::cli_abort("foobar", call=rlang::caller_env(depth))
}
main()

我终于设法完成了。

我在我的包中声明了一个全局环境,但这还不够,因为再次归因my_caller变量会导致很多错误。

在 main 函数的开头,我将全局环境中的当前环境保存为一个变量,然后我可以在下面的子函数中的任何地方调用它。

这是代码:

my_caller = rlang::env()

f = function(x, y){
  my_caller$env = rlang::current_env()
  g()
}
g = function(){
  h()
}
h = function(){
  rlang::abort("foobar", call=my_caller$env)
}

f(x=1, y=5)
#> Error in `f()`:
#>   ! foobar
#> Run `rlang::last_error()` to see where the error occurred.
rlang::last_error()
#> <error/rlang_error>
#>   Error in `f()`:
#>   ! foobar
#> ---
#>   Backtrace:
#>   1. global f(x = 1, y = 5)
#> Run `rlang::last_trace()` to see the full context.
rlang::last_trace()
#> <error/rlang_error>
#>   Error in `f()`:
#>   ! foobar
#> ---
#>   Backtrace:
#>   ▆
#> 1. └─global f(x = 1, y = 5)
#> 2.   └─global g()
#> 3.     └─global h()
#> 4.       └─rlang::abort("foobar", call = my_caller$env)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM