R 中的作用域和评估函数

nzh*_*ggh 8 r scoping

鉴于以下功能

f <- function(x) {
    g <- function(y) {
            y + z
    }
    z <- 4
    x + g(x)
 }
Run Code Online (Sandbox Code Playgroud)

如果在 R 中运行以下代码,为什么答案是 10?我对 y 如何处理这个问题有点困惑。

z <- 10
f(3)
Run Code Online (Sandbox Code Playgroud)

G. *_*eck 9

R 使用词法范围,这意味着如果一个对象被引用但未在函数中定义,那么它会在定义函数的环境中查找,而不是在调用它的环境中。

z 在 g 中引用但未在 g 中定义,因此它查看定义 g 的环境,即 f 中的环境,因此 g 使用 z = 4。

实际上,在这种情况下,定义 g 的环境与调用 g 的环境相同,因此无论您怎么看,都必须使用 z = 4。如果函数默认使用全局环境来查找函数中未定义的对象,那么它将使用 z = 10 但这不是 R 的工作方式。

让它以不同的方式工作

如果出于某种原因,您想强制 g 在调用 f 的环境中查找 z,那么您可以这样做( whereparent.frame()指的是调用 f 的环境)。

f2 <- function(x, envir = parent.frame()) {
    g <- function(y) {
            y + with(envir, z)
    }
    z <- 4
    x + g(x)
 }
 z <- 10
 f2(3)
 ## [1] 16
Run Code Online (Sandbox Code Playgroud)

或者我们可以使用y + envir$z除了它只会在父框架中而不是在其祖先中with查找,而如果在父框架中找不到,则将在父框架的祖先中查找。

另一种方法是像这样更改 g 的环境,以便它查找envir在 g 中找不到的对象:

f3 <- function(x, envir = parent.frame()) {
    g <- function(y) {
            y + z
    }
    environment(g) <- envir
    z <- 4
    x + g(x)
 }
 z <- 10
 f3(3)
 ## [1] 16
Run Code Online (Sandbox Code Playgroud)