我正在从事一个项目,其中有一些全局任务,我遇到了一些奇怪的事情。我希望有人能帮助我。
我写了这个玩具示例来演示这个问题:
x <- 1:3 ; x <- c(1, 2, 5) # this works fine
x <- 1:3 ; x[3] <- 5 # this works fine
x <<- 1:3 ; x <<- c(1, 2, 5) # this works fine
x <<- 1:3 ; x[3] <<- 5 # this does not work
# Error in x[3] <<- 5 : object 'x' not found
same.thing.but.in.a.function = function() {
x <<- 1:3
x[3] <<- 5
}
same.thing.but.in.a.function(); x
# works just fine
因此,似乎不可能使用全局赋值来更改向量的一部分 - 除非该赋值包含在函数中。谁能解释一下为什么会这样?
最佳答案
我发现了问题。
基本上,在<<-
的这种表现形式中(更准确地称为“ super 赋值运算符”而不是“全局赋值运算符”),它实际上在尝试访问变量时跳过检查全局环境。
在 R Language Definition 的第 19 页上,它指出以下内容:
x <<- data.frame(0, 0, 0) # (I added this so the code can be run)
names(x)[3] <<- "Three"
相当于
x <<- data.frame(0, 0, 0) # (I added this so the code can be run)
`*tmp*` <<- get(x, envir=parent.env(), inherits=TRUE)
names(`*tmp*`)[3] <- "Three"
x <<- `*tmp*`
rm(`*tmp*`)
当我尝试运行这四行时,它抛出了一个错误 -- parent.env
需要一个参数并且没有默认值。我只能假设该文档是在 parent.env()
的时间编写的。包含其第一个参数的默认值。但我可以有把握地猜测默认值是 environment()
它返回当前环境。然后它再次抛出错误 - x
需要用引号引起来。所以我也解决了这个问题。现在,当我运行第一行时,它会抛出与我最初遇到的相同的错误消息,但包含更多详细信息:
# Error in get("x", envir = parent.env(environment()), inherits = TRUE) :
# object 'x' not found
这是有道理的 -- environment()
本身返回 .GlobalEnv
,所以parent.env(.GlobalEnv)
完全错过全局环境,而是返回最近加载的包环境。然后,从inherits
开始设置为TRUE
,get()
函数不断向上,搜索每个加载的包环境,最终到达空环境,此时它仍然没有找到 x
。因此出现错误。
自 parent.env(environment())
将返回.GlobalEnv
(或其下面的另一个环境)只要您在本地环境中启动,当从本地环境内部运行相同的行时,就不会出现同样的问题:*
local({
x <<- data.frame(0, 0, 0) # (I added this so the code can be run)
`tmp` <<- get("x", envir=parent.env(environment()), inherits=TRUE)
names(`tmp`)[3] <- "Three"
x <<- `tmp`
rm(`tmp`)
})
x
# X0 X0.1 Three
# 1 0 0 0
# so, it works properly
相反,当 <<-
通常使用,在幕后没有发生额外的子集代码,并且它首先尝试访问当前环境(可能是全局环境)中的值,然后再向上移动。因此在这种情况下,它不会遇到跳过全局环境的问题。
* 我必须将变量从 *tmp*
更改为至tmp
因为代码中的幕后操作之一使用了*tmp*
变量,然后删除它,所以 *tmp*
在第 3 行中间消失,因此当我尝试访问它时它会抛出错误。
关于R:向量元素的全局分配仅在函数内部有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44983596/