这里有四个函数,后者包含了前者。
a <- 0
f1 <- function(expr) {
a1 <- 1
eval(expr)
}
f2 <- function(expr) {
a2 <- 2
f1(expr)
}
f3 <- function(expr) {
a3 <- 3
f2(expr)
}
f4 <- function(expr) {
a4 <- 4
f3(expr)
}
执行以下体验:
> f4(a)
0
按预期工作。但是如果我们打电话
F4(a4)的 eval(expr)出错:找不到对象'a4'
> f4(a3)
Error in eval(expr) : object 'a3' not found
...
> f2(a2)
Error in eval(expr) : object 'a2' not found
> f2(a1)
Error in eval(expr) : object 'a1' not found
> f1(a1)
Error in eval(expr) : object 'a1' not found
我检查每个函数体的局部环境和父环境f3
的父框架是f4
的本地环境,......,f1
的父元素是{{ 1}}的身体。这是否清楚地解释了为什么会这样?我如何摆脱这个问题,使代码工作的目的是函数调用应该允许后续函数(如f2
)找到定义的符号(例如f3
)?
答案 0 :(得分:8)
我强烈建议您花一些时间阅读Advanced R: Environments。
首先,当我运行f1(a1)
时,我也找不到“对象'a1';当你超越时,不是“1”。
问题是默认情况下,R使用函数的封闭环境解析变量。函数的封闭环境是在定义函数时确定的,而不是在调用函数时确定的。因此,它不会通过调用链来解析变量名称。您可以使用parent.frame()
环境显式查找调用父级,但这些环境不会在嵌套函数调用中链接在一起。
与get()
通过沿着封闭的父环境走上来循环变量的方式相同,您可以创建自己的函数来调用调用环境并查看哪些变量可用。
call.get <- function(val) {
for(i in 1:sys.nframe()) {
if (exists(val, envir=sys.frame(i), inherits=F)) {
return(get(val, envir=sys.frame(i)))
}
}
return(NULL)
}
call.ls <- function(val) {
vars<-lapply(1:sys.nframe(), function(i) ls(envir=parent.frame(i)))
return(sort(unique(unlist(vars))))
}
然后,如果您执行类似
的操作f1 <- function(expr) {
a1 <- 1
call.ls()
}
f2 <- function(expr) {
a2 <- 2
f1(expr)
}
f3 <- function(expr) {
a3 <- 3
f2(expr)
}
f4 <- function(expr) {
a4 <- 4
f3(expr)
}
f4(1)
你会得到
"a1" "a2" "a3" "expr" "FUN" "val" "X"
你可以使用
call.get("a3")
从父调用帧中获取其中一个变量。
但另一个问题是,当您调用子函数时,您将触发对expr参数的求值。当你这样做
f2 <- function(expr) {
a2 <- 2
f1(expr)
}
评估expr
环境中的f2
并将结果传递给f1
。那时你正在失去评估。通过延迟评估的最简单方法是使用“...”。像
f1 <- function(...) {
a1 <- 1
expr<-deparse(substitute(...))
call.get(expr)
}
f2 <- function(...) {
a2 <- 2
f1(...)
}
f2(a1)
# [1] 1
f2(a2)
# [1] 2
否则,您需要使用do.call
f1 <- function(expr) {
a1 <- 1
expr<-deparse(substitute(expr))
call.get(expr)
}
f2 <- function(expr) {
expr<-substitute(expr)
a2 <- 2
do.call(f1, list(expr))
}
f2(a1)
# [1] 1
f2(a2)
# [1] 2