我的解决方案是递归地寻找环境。我们可以这样做,因为必须在可见/已知的地方创建附加/新环境。不过,可能还有一些较小的边缘情况,例如函数或 R6 类中的环境:
fun <- function() {
ee <- new.env()
fun2 <- function() {
eee <- new.env()
}
return(1)
}
另一件事是抓住例如函数体的环境,在 {} 内。它将在函数评估而不是创建期间创建。这几乎是不可能的。
我要求将对象识别为环境 - is.environment 和 inherits(e, "environment")。后一种条件可以保护我们免受像 ggproto 这样的带有 ggplot2 的对象的攻击。
set.seed(1234)
# New environments - x7
#######################
eval(quote(ee <- new.env(parent = baseenv())))
eval(quote(ee1 <- new.env(parent = baseenv())), envir = ee)
ee2 <- new.env()
ee3 <- new.env(parent = ee2)
eval(quote(ee4 <- new.env(parent = baseenv())), envir = ee3)
eval(quote(ee5 <- new.env()), envir = baseenv())
eval(quote(ee6 <- new.env(parent = .GlobalEnv)), envir = ee3)
#######################
subenv <- function(env) {
envs <- unique(Filter(function(e) is.environment(e) && inherits(e, "environment"), lapply(ls(env), function(x) get(x, env))))
unlist(append(envs, lapply(envs, subenv)))
}
search_all = function() {
ees <- unlist(append(.GlobalEnv, rlang::env_parents(.GlobalEnv)))
unname(unlist(lapply(ees, subenv)))
}
library(ggplot2)
search_all()
结果:
> search_all()
[[1]]
<environment: 0x7f9c75e66e10>
[[2]]
<environment: 0x7f9c75e65600>
[[3]]
<environment: 0x7f9c75e68e80>
[[4]]
<environment: 0x7f9c75e65e88>
[[5]]
<environment: 0x7f9c75e67ec0>
[[6]]
<environment: 0x7f9c75e6df38>
[[7]]
<environment: 0x7f9c75e6ef30>
编辑:
此功能可用于最大化环境可见性。
new.env <- function(...) {
ee <- base::new.env(...)
if(!identical(parent.frame(), .GlobalEnv)) {
assign(paste0("env_", data.table::address(ee)), ee, envir = .GlobalEnv)
}
ee
}
不幸的是,当构建某些包时,它将默认使用 base::new.env。即便是assignInNamespace 在这里也可能不尽如人意。