145

我是 R 的新手,我对 R 中局部和全局变量的使用感到很困惑。

我在互联网上阅读了一些帖子,说如果我使用=或者<-我将在当前环境中分配变量,并且<<-我可以在函数内部访问全局变量。

但是,正如我记得在 C++ 中,每当您在括号内声明变量时,都会出现局部变量{},所以我想知道这对于 R 是否相同?或者仅仅是R中的函数,我们有局部变量的概念。

我做了一个小实验,似乎表明只有括号是不够的,我有什么问题吗?

{
   x=matrix(1:10,2,5)
}
print(x[2,2])
[1] 4
4

3 回答 3

168

在函数内部声明的变量是该函数的局部变量。例如:

foo <- function() {
    bar <- 1
}
foo()
bar

给出以下错误:Error: object 'bar' not found

如果你想创建bar一个全局变量,你应该这样做:

foo <- function() {
    bar <<- 1
}
foo()
bar

在这种情况下bar,可以从函数外部访问。

但是,与 C、C++ 或许多其他语言不同,括号不能确定变量的范围。例如,在以下代码片段中:

if (x > 10) {
    y <- 0
}
else {
    y <- 1
}

y声明后仍可访问if-else

正如您所说,您还可以创建嵌套环境。您可以查看这两个链接以了解如何使用它们:

  1. http://stat.ethz.ch/R-manual/R-devel/library/base/html/environment.html
  2. http://stat.ethz.ch/R-manual/R-devel/library/base/html/get.html

这里有一个小例子:

test.env <- new.env()

assign('var', 100, envir=test.env)
# or simply
test.env$var <- 100

get('var') # var cannot be found since it is not defined in this environment
get('var', envir=test.env) # now it can be found
于 2012-06-05T20:20:40.810 回答
148

<-在当前环境中进行赋值。

当你在一个函数中时,R 会为你创建一个新环境。默认情况下,它包括创建它的环境中的所有内容,因此您也可以使用这些变量,但您创建的任何新内容都不会写入全局环境。

在大多数情况下<<-,即使您在函数内部,也会分配给全局环境中已经存在的变量或在全局环境中创建变量。然而,它并不像那样简单。它的作用是检查父环境以查找具有感兴趣名称的变量。如果它在您的父环境中找不到它,它会转到父环境的父环境(在创建函数时)并在那里查找。它继续向上到全局环境,如果在全局环境中找不到它,它将在全局环境中分配变量。

这可能说明正在发生的事情。

bar <- "global"
foo <- function(){
    bar <- "in foo"
    baz <- function(){
        bar <- "in baz - before <<-"
        bar <<- "in baz - after <<-"
        print(bar)
    }
    print(bar)
    baz()
    print(bar)
}
> bar
[1] "global"
> foo()
[1] "in foo"
[1] "in baz - before <<-"
[1] "in baz - after <<-"
> bar
[1] "global"

我们第一次打印 bar 我们还没有调用foo所以它应该仍然是全局的——这是有道理的。我们第二次打印它是foo在调用之前的内部,baz所以“in foo”的值是有意义的。下面是我们看到<<-实际在做什么的地方。打印的下一个值是“in baz - before <<-”,即使 print 语句出现在<<-. 这是因为<<-不查看当前环境(除非您在全局环境中,这种情况下的<<-行为类似于<-)。所以bazbar 的值内部保持为“in baz - before <<-”。一旦我们调用bazbar inside of 的副本,foo就会更改为“in baz”,但我们可以看到全局bar没有变化。barfoo当我们创建时,它在父环境中定义,baz所以这是bar<<-看到的第一个副本,因此是它分配给的副本。所以<<-不仅仅是直接分配给全局环境。

<<-很棘手,如果可以避免,我不建议使用它。如果您真的想分配给全局环境,您可以使用 assign 函数并明确告诉它您要全局分配。

现在我将其更改<<-为分配语句,我们可以看到它有什么效果:

bar <- "global"
foo <- function(){
    bar <- "in foo"   
    baz <- function(){
        assign("bar", "in baz", envir = .GlobalEnv)
    }
    print(bar)
    baz()
    print(bar)
}
bar
#[1] "global"
foo()
#[1] "in foo"
#[1] "in foo"
bar
#[1] "in baz"

因此,foo即使在调用baz. 这是因为我们assign从来没有考虑过 foo 内部的副本,bar因为我们告诉了它在哪里看。但是,这一次全局环境中 bar 的值发生了变化,因为我们在那里显式分配。

现在您还询问了有关创建局部变量的问题,您也可以很容易地做到这一点,而无需创建函数……我们只需要使用该local函数。

bar <- "global"
# local will create a new environment for us to play in
local({
    bar <- "local"
    print(bar)
})
#[1] "local"
bar
#[1] "global"
于 2012-06-05T20:56:00.007 回答
3

沿着同样的路线多一点

attrs <- {}

attrs.a <- 1

f <- function(d) {
    attrs.a <- d
}

f(20)
print(attrs.a)

将打印“1”

attrs <- {}

attrs.a <- 1

f <- function(d) {
   attrs.a <<- d
}

f(20)
print(attrs.a)

将打印“20”

于 2018-03-15T07:47:29.587 回答