我有以下代码片段,灵感来自我的原始代码。
func2 <- function(foos) {
for (foo in foos)
print(eval(parse(text = foo)))
return(foos)
}
func1 <- function(vec) {
text3_obj <- 'text3'
vec <- c(vec, c('text3_obj'))
return(func2(vec))
}
text1_obj <- 'text1'
text2_obj <- 'text2'
func1(c('text1_obj', 'text2_obj'))
在主代码中,我创建了2个对象(text1_obj
& text2_obj
),并将他们的名字传递给 func1()
. 这个函数在向量中添加另一个对象后,调用了 func2()
. 在 func2()
我只是简单地打印对象的值。下面是这段代码的输出。
[1] "text1"
[1] "text2"
Error in eval(parse(text = foo)) : object 'text3_obj' not found
在进入调试模式后,我发现即使 exists('text3_obj')
从内部 func2()
抛出错误。所以我有两个问题。
func1()
的直系亲属环境。func2()
;为什么 text3_obj
是不能在 func2()
. 即使是更高的全局环境变量也是可以解析的,如 text1_obj
.exists('text3_obj', where = parent.frame())
和 eval(parse(text = 'text3_obj'), parent.frame())
你混淆了 "调用环境 "和 "包围环境"。 查看Hadley的 "Advanced R "一书中的这些术语。
http:/adv-r.had.co.nzEnvironments.html
调用环境 "是指函数被调用的环境,并由一个名字很不幸的函数 parent.frame
. 然而,调用环境并不用于词法作用域。
包围环境 "是创建函数的环境,用于词法作用域。 您已经创建了两个 func1
和 func2
的全局环境中。 因此,全局环境是这两个函数的 "包围环境",并将用于词法范围的确定。无论调用环境如何!
如果你想 func2
的执行环境来使用 func1
对于词法范围,您有(至少)两种选择。 您可以创建 func2
内 func1
func1 <- function(vec) {
func2 <- function(foos) {
for (foo in foos)
print(eval(parse(text = foo)))
return(foos)
}
text3_obj <- 'text3'
vec <- c(vec, c('text3_obj'))
return(func2(vec))
}
那么你的测试就会像预期的那样工作。
> text1_obj <- 'text1'
> text2_obj <- 'text2'
> func1(c('text1_obj', 'text2_obj'))
[1] "text1"
[1] "text2"
[1] "text3"
[1] "text1_obj" "text2_obj" "text3_obj"
或者,你可以创建 func2
并从内部重新分配它的 "包围环境"。func1
.
func2 <- function(foos) {
for (foo in foos)
print(eval(parse(text = foo)))
return(foos)
}
func1 <- function(vec) {
text3_obj <- 'text3'
vec <- c(vec, c('text3_obj'))
environment(func2) <- environment()
return(func2(vec))
}
这也能达到预期的效果。
在编写演示代码时,我发现了一个有趣的小插曲......。 似乎当你重新分配环境的 func2
从内部 func1
的副本,R创建了一个 func2
在执行环境中 func1
. 当你回到控制台的时候,原来的封闭环境的 func2
保持不变。 证人。
a = function() {
print(identical(environment(a), globalenv()))
}
b = function(x) {
environment(a) <- environment()
a()
}
测试: a()
和 b()
:
> a()
[1] TRUE
> b()
[1] FALSE
> a()
[1] TRUE
>
这不是我所期望的,但看起来R的行为非常出色。a()
的执行环境将被永久地改变为以下环境 b()
和 FALSE
早该退回 a()
被称为。
如果事实上,原来你可以强行将原来的 a()
在全球环境中使用 <<-
:
a = function() {
print(identical(environment(a), globalenv()))
}
b = function(x) {
# set a variable in the execution environment of b() for use later...
montePython = "I'm not dead yet!!"
# change the enclosing environment of a() in the global environment
# rather than making a local copy of a() in b()'s execution environment.
environment(a) <<- environment()
a()
}
测试 a()
和 b()
:
> a()
[1] TRUE
> b()
[1] FALSE
> a()
[1] FALSE
>
有意思的是,这意味着,《公约》的执行环境(通常是临时性的),将在《公约》的框架内进行。b()
记忆犹新 b()
终止,因为 a()
仍然引用环境,所以不能被垃圾收集。 证人:
> environment(a)$montePython
[1] "I'm not dead yet!!"