R:向量元素的全局赋值仅在函数内部起作用

时间:2017-07-08 07:18:28

标签: r global-variables variable-assignment environment

我正在开展一项全球任务的项目,我遇到了一些奇怪的事情。我希望有人可以帮助我。

我写了这个玩具示例来证明这个问题:

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

因此,似乎不可能使用全局赋值来更改向量的一部分 - 除非该赋值包含在函数中。任何人都可以解释为什么会这样吗?

2 个答案:

答案 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设置为TRUEget()函数会继续上升,在最终到达空白环境之前搜索每个已加载的包环境,此时它仍未找到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    
顺便说一句 - 我会建议这些精彩的讨论,以便更好地理解和正确使用<<-运算符 -