R语言中嵌入列表的闭包运行异常是否属于语言本身的bug?
R循环中闭包取值异常的原因说明
这不是R语言的bug,属于R的惰性求值特性与闭包环境绑定规则的正常表现。
问题根因
R中函数的参数默认采用延迟求值(Promise)机制,同时闭包捕获的是变量的引用而非创建时的瞬时值:
- 你定义的
fFactory函数的参数letter在传入时没有被强制求值,本质是绑定到循环环境中同一个letter变量的Promise - 循环执行时只是不断修改同一个
letter变量的值,所有生成的闭包内的letter参数都指向这个全局的循环变量 - 只有当你实际调用闭包函数时,才会触发Promise求值,此时循环已经执行完毕,
letter的值固定为最后一次迭代的z,因此所有闭包的返回结果都一致。
修复方案
最简单的修复方式是在工厂函数内对入参强制求值,固化当前迭代的值:
fFactory <- function(letter) { # 添加强制求值语句,将当前参数值固化到当前函数环境 force(letter) function(Param) { paste("Enclosed variable:", letter, "/ function parameter:", Param) } }
修改后再执行循环生成列表代码,即可得到预期结果:
> l[["a"]]$FUN("toto") [1] "Enclosed variable: a / function parameter: toto"
你也可以用lapply替代for循环实现同样效果,lapply每次迭代会生成独立的执行环境,不会出现变量复用的问题:
l <- lapply(letters, function(cur_letter) { list(FUN = fFactory(cur_letter)) }) names(l) <- letters
内容的提问来源于stack exchange,提问作者David Dorchies
相关产品推荐
相关产品推荐

