R封闭范围

时间:2018-08-15 20:22:22

标签: r closures

我试图理解R中的闭包。

有人可以向我解释为什么这样的代码(1):

vars <- c("one", "two")
funcs <- list()

for (v in vars) {
  funcs[[length(funcs) + 1]] <- function() {
    print(v)
  }
}

funcs[[1]]()
funcs[[2]]()

返回

[1] "two"
[1] "two"

但遵循以下代码(2):

vars <- c("one", "two")
funcs <- list()

getFunc <- function(v) {
  v_i <- v
  function() {
    print(v_i)
  }
}

for (v in vars) {
  funcs[[length(funcs) + 1]] <- getFunc(v)
}

funcs[[1]]()
funcs[[2]]()

返回:

[1] "one"
[1] "two"

此外,此代码仍仅打印“两个”(3):

vars <- c("one", "two")
funcs <- list()

for (v in vars) {
  v_i <- v
  funcs[[length(funcs) + 1]] <- function() {
    print(v_i)
  }
}

funcs[[1]]()
funcs[[2]]()

这也只打印“两个”(4):

vars <- c("one", "two")
funcs <- list()

getFunc <- function(v) {
  function() {
    print(v)
  }
}

for (v in vars) {
  funcs[[length(funcs) + 1]] <- getFunc(v)
}

funcs[[1]]()
funcs[[2]]()

我猜想v会被重用,因此它总是指向内存中的相同空间。但是我们是否可以确定v始终是列表的最后一个值-它会在时间上保持不变或不稳定?

(3)意味着不足以将值分配给其他变量,它必须位于单独的函数中。

(4)表示函数的参数也已重用。

1 个答案:

答案 0 :(得分:2)

全局环境中的v在任何时候都只有一个值,但是随着for循环的改变,v的值也会变化。在第一次迭代中v"one",在第二次迭代中它是"two",并且由于v随后没有更改,因此它保持在值"two"。现在,

1):在第一种情况下,当您致电funcs[[1]]()时,它会在v中查找funcs[[1]],因此找不到,因此它会在{ {1}},这就是全球环境。

environment(funcs[[1]])

运行environment(funcs[[1]]) ## <environment: R_GlobalEnv> 时,在全局环境中v的值为“ two”,因此将其打印出来。

2)在第二个示例中,当您调用funcs[[1]]时,它会在funcs[[1]]()中查找v_i,而再次找不到它,便会在{ {1}},但现在funcs[[1]]的环境是environent(funcs[[1]])中的运行时环境。  每次运行funcs[[1]]时,环境都会不同。无论如何,在该环境getfunc中,其值均为getfunc,因此它将打印出来。

v_i

3)第三个示例与第一个示例基本相同。 "one"在全局环境中,在运行environment(funcs[[1]]) ## <environment: 0x00000000097418d0> 时具有值v_i

4)在第四个示例中,"two"funcs[[1]()内的运行时环境;但是,由于在调用environment(funcs[[1]])之前尚未访问getfunc的{​​{1}}参数,因此v仍然是未评估的承诺。最终调用getfunc时,它需要使用funcs[[1]]来评估诺言,此时vfuncs[[1]]