我正在开展一项全球任务的项目,我遇到了一些奇怪的事情。我希望有人可以帮助我。
我写了这个玩具示例来证明这个问题:
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
因此,似乎不可能使用全局赋值来更改向量的一部分 - 除非该赋值包含在函数中。任何人都可以解释为什么会这样吗?
答案 0 :(得分:3)
我发现了问题。
基本上,在<<-
(更准确地称为&#34;超级运算符&#34;而不是&#34;全局赋值运算符&#34;)的这种表现形式中,它实际上会跳过检查尝试访问变量时的全局环境。
在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行的中间消失,因此当我尝试访问它时会抛出错误。
答案 1 :(得分:0)
如果您更改为单箭头分配,那么它可以正常工作
x <<- 1:3 ; x[3] <- 5
顺便说一句 - 我会建议这些精彩的讨论,以便更好地理解和正确使用<<-
运算符 -