R 环境和作用域

为了正确编写函数并避免不寻常的错误,我们需要了解 R 中的环境和作用域概念。

R 编程环境

环境可以被认为是对象(函数、变量等)的集合。

当我们第一次启动 R 解释器时,就会创建一个环境。我们定义的任何变量现在都存在于这个环境中。

在 R 命令提示符下可用的顶层环境是全局环境,称为 R_GlobalEnv

全局环境在 R 代码中也可以称为 .GlobalEnv

我们可以使用 ls() 函数来显示当前环境中定义了哪些变量和函数。

此外,我们还可以使用 environment() 函数来获取当前环境。

> a <- 2
> b <- 5
> f <- function(x) x<-0

> ls()
[1] "a" "b" "f"

> environment()
<environment: R_GlobalEnv>

> .GlobalEnv
<environment: R_GlobalEnv>

在上面的示例中,我们可以看到 abf 存在于 R_GlobalEnv 环境中。

请注意,x(函数参数中的)不在全局环境中。当我们定义一个函数时,会创建一个新环境。

在上面的示例中,函数 f 在全局环境中创建了一个新环境。

实际上,环境有一个帧(frame),其中包含定义的所有对象,还有一个指向其封闭(父)环境的指针。

因此,x 存在于函数 f 创建的新环境的帧中。此环境还将有一个指向 R_GlobalEnv 的指针。


示例:环境的级联

f <- function(f_x){
   g <- function(g_x){
       print("Inside g")
       print(environment())
       print(ls())
   }
   g(5)
   print("Inside f")
   print(environment())
   print(ls())
}

现在,当我们在命令提示符下运行时,我们得到:

> f(6)
[1] "Inside g"
<environment: 0x0000000010c2bdc8>
[1] "g_x"
[1] "Inside f"
<environment: 0x0000000010c2a870>
[1] "f_x" "g"  

> environment()
<environment: R_GlobalEnv>

> ls()
[1] "f"

这里,我们在 f 中定义了函数 g,很明显它们都有不同的环境,并且在其各自的帧中包含不同的对象。


R 编程作用域

让我们看一个例子。

outer_func <- function(){
   b <- 20
   inner_func <- function(){
       c <- 30
   }
}
a <- 10

全局变量

全局变量是在程序执行期间始终存在的变量。它可以从程序的任何部分进行更改和访问。

但是,全局变量也取决于函数的视角。

例如,在上面的示例中,从 inner_func() 的角度来看,ab 都是全局变量。

然而,从 outer_func() 的角度来看,b 是局部变量,只有 a 是全局变量。变量 couter_func() 完全不可见。


局部变量

另一方面,局部变量是在程序特定部分(如函数)内存在的变量,并在函数调用结束时被释放。

在上面的程序中,变量 c 被称为局部变量。

如果我们使用 inner_func() 函数为变量赋值,更改将仅是局部的,并且无法在函数外部访问。

即使全局变量和局部变量的名称匹配,情况也是如此。

例如,如果我们有一个如下的函数:

outer_func <- function(){
   a <- 20
   inner_func <- function(){
       a <- 30
       print(a)
   }
   inner_func()
   print(a)
}

当我们调用它时:

> a <- 10

> outer_func()
[1] 30
[1] 20

> print(a)
[1] 10

我们看到变量 a 是在两个函数的环境帧中本地创建的,与全局环境帧不同。


访问全局变量

可以读取全局变量,但当我们尝试为其赋值时,会创建一个新的局部变量。

要对全局变量进行赋值,需要使用超赋值运算符 `<<-`。

当在函数中使用此运算符时,它会在父环境帧中查找变量,如果未找到,它会继续搜索下一级,直到达到全局环境。

如果仍然找不到该变量,则将在全局级别创建并赋值。

outer_func <- function(){
   inner_func <- function(){
       a <<- 30
       print(a)
   }
   inner_func()
   print(a)
}

运行此函数后:

> outer_func()
[1] 30
[1] 30
> print(a)
[1] 30

当在 inner_func() 中遇到语句 a <<- 30 时,它会查找 outer_func() 环境中的变量 a

当搜索失败时,它会在 R_GlobalEnv 中进行搜索。

由于 a 在全局环境中也未定义,因此它在此处被创建并赋值,现在它既可以从 inner_func() 内部引用和打印,也可以从 outer_func() 引用和打印。

你觉得这篇文章有帮助吗?

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战