我试图理解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)表示函数的参数也已重用。
答案 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]]
来评估诺言,此时v
是funcs[[1]]
。