R语言中get(..., inherits=TRUE)无法找到闭包作用域变量的解决方法
理解R的作用域问题及解决方案
首先得澄清你对inherits=TRUE的误解:它并不是沿着调用栈查找,而是沿着函数的定义环境继承链往上找。R是词法作用域语言,函数的执行环境默认是它被定义的环境(这里f定义在全局REPL,所以它的环境就是全局环境),而不是调用它的环境(g的函数环境)。所以当f里调用get('y', inherits=TRUE)时,它只会从全局环境开始,往上遍历继承链(比如全局→基础包环境),完全不会去看调用它的g的环境,这就是为什么y在g里定义时找不到的原因。
下面给你几个可行的解决方案,根据你的场景选择:
方案1:修改函数,让get从调用者环境开始查找
如果可以修改f的代码,直接给get()指定envir参数为调用者的环境:
f = function() { print(get('y', envir = parent.frame(), inherits=TRUE)) }
parent.frame()会返回调用f的那个函数的环境(也就是g的局部环境),这样get会先在g的环境里找y,找不到再沿着继承链往上走,完美解决问题。
方案2:调用函数时显式指定执行环境
如果你没法修改f(比如它是某个库的内置函数),可以在g里用eval或者do.call强制f在g的环境里执行:
g = function() { y = 3; # 用eval执行f的函数体,环境设为g的局部环境 eval(body(f), envir = environment()) }
或者用do.call的方式:
g = function() { y = 3; do.call(f, args = list(), envir = environment()) }
这样f执行时的环境就是g的局部环境,自然能找到y。
方案3:适配库函数的公式解析场景
你提到背景是某个库解析公式时用了get(),这种情况很多库的公式相关函数其实都提供了envir参数,比如model.frame、lm等。你只需要在调用这些库函数时,把当前函数的环境传进去就行:
# 举个例子,假设你用的是类似这样的库函数调用 my_function = function() { y = 3 formula = ~ y # 把当前环境(my_function的局部环境)传给envir参数 result = some_library_function(formula, envir = environment()) }
这样库函数里的get()就会从你指定的环境开始查找变量,而不是默认的全局环境。
补充:遍历调用栈的兜底方案
如果上面的方法都不适用,还可以手动遍历调用栈的所有环境来查找变量:
f = function() { # 遍历当前所有调用栈环境 for (frame_idx in seq_len(sys.nframe())) { current_env = sys.frame(frame_idx) if (exists('y', envir = current_env, inherits = FALSE)) { print(get('y', envir = current_env)) return() } } # 如果遍历完调用栈都没找到,再走默认继承链 print(get('y', inherits = TRUE)) }
不过这个方法比较繁琐,除非万不得已不推荐使用。
内容的提问来源于stack exchange,提问作者dwf
相关产品推荐
相关产品推荐

