为什么R语言中未使用!!运算符时glue无法找到fun_C_notok中的x变量
问题原因
这个问题的核心是glue的变量查找逻辑和rlang非标准求值带来的环境错位共同导致的,具体可以拆解为三点:
- 你看到
list(...)可以正常打印x、y的值是正常的,因为list()会强制求值所有传入...的参数,不管参数的绑定环境是什么,都能拿到实际值。 - 但
glue的变量查找逻辑不同:它会优先把...里的参数放到一个临时求值环境,再把该环境的父环境设为你传入的.envir(默认是调用glue时的父环境,也就是fun_A的调用环境)。当你在fun_B里用rlang::enquo()捕获fun_A的调用表达式、再用eval_tidy()执行时,fun_A的调用环境是rlang创建的临时mask环境,这个环境里没有x、y变量,而glue在eval_tidy的上下文中无法正确读取...里的变量,才会报找不到对象的错误。 - 加了
!!运算符后能正常运行的原因也很简单:!!是rlang的即时求值运算符,会在enquo捕获fun_A调用表达式的阶段,就把x、y的实际值注入到表达式里,这时候传入fun_A的x、y不再是指向fun_C_notok环境的变量引用,而是固定的常量值,glue就可以正常识别匹配了。
可选解决方案
如果你不想每次调用都写!!,可以直接修改fun_A的实现,两种修改方式都可以:
- 显式指定
glue的求值环境为fun_A的当前执行环境:
fun_A <- function(my_string, ..., z = NULL){ print(paste0("z value: ", as.character(z))) print(list(...)) # 新增.envir参数指定为当前环境 my_string <- glue::glue(my_string, ..., .envir = environment()) return(my_string) }
- 先把
...强制求值为列表,再用!!!展开传入glue:
fun_A <- function(my_string, ..., z = NULL){ print(paste0("z value: ", as.character(z))) dots <- list(...) print(dots) # 强制求值后展开传入 my_string <- glue::glue(my_string, !!!dots) return(my_string) }
以上两种修改方式都可以让fun_C_notok不加!!也能正常运行。
内容的提问来源于stack exchange,提问作者Damien Debot
相关产品推荐
相关产品推荐

