简体   繁体   English

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

[英]R: Global assignment of vector element works only inside a function

I'm working on a project where there are some global assignments, and I ran into something sort of odd. 我正在做一个有一些全球任务的项目,但是遇到了一些奇怪的事情。 I was hoping someone could help me with it. 我希望有人可以帮助我。

I wrote this toy example to demonstrate the problem: 我写了这个玩具示例来演示这个问题:

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

So, it seems it's not possible to change part of a vector using a global assignment -- unless that assignment is contained within a function. 因此,似乎不可能使用全局赋值来更改矢量的一部分-除非该赋值包含在函数中。 Can anyone explain why this is the case? 谁能解释为什么会这样?

I figured out the problem. 我解决了这个问题。

Basically, in this manifestation of <<- (which is more accurately called the "superassignment operator" rather than the "global assignment operator"), it actually skips checking the global environment when trying to access the variable. 基本上,在<<- (更准确地称为“超级赋值运算符”而不是“全局赋值运算符”)的这种表现形式中,实际上在尝试访问变量时会跳过对全局环境的检查。

On page 19 of R Language Definition , it states the following: 在“ R语言定义”的第19页上,其内容如下:

x <<- data.frame(0, 0, 0) # (I added this so the code can be run)
names(x)[3] <<- "Three"

is equivalent to 相当于

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*`)

When I tried to run those four lines, it threw an error -- parent.env requires an argument and has no default. 当我尝试运行这四parent.env ,它引发了一个错误parent.env需要一个参数,并且没有默认值。 I can only assume that the documentation was written at a time when parent.env() contained a default value for its first argument. 我只能假设文档是在parent.env()包含其第一个参数的默认值的时候parent.env() But I can safely guess that the default would have been environment() which returns the current environment. 但是我可以放心地猜测默认值是返回当前环境的environment() It then throws an error again -- x needs to be in quotes. 然后,它再次引发错误x必须用引号引起来。 So I fixed that too. 所以我也解决了。 Now, when I run the first line, it throws the same error message as I encountered originally, but with more detail: 现在,当我运行第一行时,它会引发与我最初遇到的错误消息相同的消息,但会包含更多详细信息:

# Error in get("x", envir = parent.env(environment()), inherits = TRUE) :
#   object 'x' not found

This makes sense -- environment() itself returns .GlobalEnv , so parent.env(.GlobalEnv) misses out on the global environment entirely, instead returning the most recently loaded package environment. 这很有道理.GlobalEnv environment()本身返回.GlobalEnv ,因此parent.env(.GlobalEnv)完全错过了全局环境,而是返回了最近加载的包环境。 Then, since inherits is set to TRUE , the get() function keeps going up the levels, searching through each of the loaded package environments before eventually reaching the empty environment, and at that point it has still not found x . 然后,由于将inherits设置为TRUE ,因此get()函数不断升级,在最终到达空环境之前搜索每个已加载的包环境,到那时仍未找到x Thus the error. 因此错误。

Since parent.env(environment()) will return .GlobalEnv (or another environment below it) as long as you start inside a local environment, this same problem does not occur when the same lines are run from inside a local environment:* 由于只要您在本地环境中启动, 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

In contrast, when <<- is used in general, there is no extra subsetting code that occurs behind the scenes, and it first attempts to access the value in the current environment (which might be the global environment), before moving upwards. 相反,通常使用<<-时,幕后不会出现多余的子集代码,在向上移动之前,它首先尝试访问当前环境(可能是全局环境)中的值。 So in that situation, it doesn't run into the problem where it skips the global environment. 因此,在那种情况下,它不会遇到跳过全局环境的问题。

* I had to change the variable from *tmp* to tmp because one of the behind-the-scenes operations in the code uses the *tmp* variable and then removes it, so *tmp* disappears in the middle of line 3 and so it throws an error when I then try to access it. *我不得不将变量从*tmp*更改为tmp因为代码中的幕后操作之一使用了*tmp*变量,然后将其删除,因此*tmp*在第3行的中间消失了,所以然后我尝试访问它时会引发错误。

If you change to single arrow assignment then it work 如果您更改为单箭头分配,则可以使用

x <<- 1:3 ; x[3] <- 5    

BTW - I would suggest these wonderful discussions for better understanding and proper use of <<- operator - 顺便说一句-我建议进行这些精彩的讨论,以更好地理解和正确使用<<-运算符-

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM