首页 > 解决方案 > R闭包范围

问题描述

我试图理解 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) 表示函数的参数也被重用。

标签: rclosures

解决方案


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

1)在第一种情况下,当您调用funcs[[1]]()它时,它会vfuncs[[1]]其中查找并且找不到它,因此它environment(funcs[[1]])会在全局环境中查找。

environment(funcs[[1]])
## <environment: R_GlobalEnv>

v运行时全局环境中的值funcs[[1]]是“二”,因此它会打印出来。

2)在第二个示例中,当您调用funcs[[1]]()它时,它会查找v_iinfuncs[[1]]并且找不到它,所以它会再次查找,environent(funcs[[1]])但现在的环境funcs[[1]]getfunc. 每次getfunc运行该环境都会有所不同。无论如何,在那个环境v_i中都有价值"one",所以它会打印出来。

environment(funcs[[1]])
## <environment: 0x00000000097418d0>   

3)第三个例子和第一个例子基本相同。 v_i处于全局环境中,并且"two"在运行时具有值funcs[[1]()

4)在第四个例子中environment(funcs[[1]])是运行时环境getfunc;然而,因为在被调用之前还没有访问到的v参数,所以仍然是一个未评估的承诺。当最终被调用时,它需要使用promise 被评估并且此时是.getfuncfuncs[[1]]vfuncs[[1]]vv"two"


推荐阅读