在R中如何在自定义函数内部嵌套使用rlang引用类函数?
问题根源
rlang::enquo()、rlang::ensym()的作用是捕获当前函数层级传入的参数的表达式与对应环境,不会自动穿透多层函数调用栈。
- 直接调用
fun1时,函数内部的enquo(x)捕获到的是用户传入的mpg(数据框中存在的列名表达式),解引用后可以正常匹配到对应列计算,所以运行正常。 - 调用
fun2时,你直接传递x=x给fun1,此时fun1里的enquo(x)捕获到的是fun2的形参x,而不是最外层用户传入的mpg,计算时无法匹配到数据框中的对应列,就会抛出错误。
解决方法
你只需要在中间封装层fun2里把参数的表达式正确传递到下层函数即可,有两种常用实现方式:
方法1:手动捕获后解引用传递
fun2 <- function(df, x, ...){ # 先在fun2层级捕获x的表达式 x_quo <- rlang::enquo(x) # 传递时用!!解引用,把实际的列名表达式传入fun1 out2 <- fun1(df = df, x = !!x_quo, ...) return(out2) }
方法2:使用{{(双大括号)运算符简化写法
rlang提供的双大括号运算符可以自动完成「捕获+解引用」的两步操作,代码更简洁:
fun2 <- function(df, x, ...){ out2 <- fun1(df = df, x = {{x}}, ...) return(out2) }
补充优化建议
你原来的fun1不需要同时调用enquo和ensym,直接用双大括号可以大幅简化代码:
fun1 <- function(df, x, ...){ out <- df %>% dplyr::group_by(...) %>% # {{x}} 同时处理列名赋值和计算时的引用 dplyr::summarise({{x}}:=sum({{x}}, na.rm = TRUE)) %>% dplyr::ungroup() %>% data.frame(., stringsAsFactors = FALSE) return(out) }
修改完成后调用fun2(df = head(mtcars), x = mpg, cyl, disp, hp)就能得到和fun1完全一致的输出结果。
内容的提问来源于stack exchange,提问作者Caddisfly
相关产品推荐
相关产品推荐

