使用dplyr编写自定义函数时默认参数无法被识别的问题求解
问题原因
你编写的foo()默认参数失效的核心原因是参数求值环境与dplyr数据屏蔽(data masking)环境不匹配:
- dplyr的
mutate()提供的数据屏蔽机制,仅能让直接写在mutate()调用内的变量优先从管道传入的数据框中查找 - 你没有给
foo()传参时,R会在foo()的函数内部作用域中查找默认值cyl,而foo()内部不存在该对象,因此抛出找不到对象的错误 - 你写的
foo2()可以正常运行,是因为foo2()内部调用了mutate(),且用{{x}}(准引用语法糖)捕获了x的表达式,x的默认值cyl会在foo2()内部mutate()的数据屏蔽环境中求值,所以能找到数据框的cyl列
解决方案
仅需要在原有foo()中加入准引用语法糖{{}}包裹x,即可让默认参数正常在mutate()的上下文环境中求值:
library(tidyverse) foo <- function(x = cyl){ case_when( {{x}} == 6 ~ TRUE, {{x}} == 8 ~ FALSE, {{x}} == 4 ~ NA ) } # 现在运行成功 mtcars %>% mutate(cyl_refactor = foo()) %>% select(cyl, cyl_refactor)
原理解释
{{}}是rlang包提供的准引用语法糖,等价于先执行enquo(x)捕获参数的表达式(而不是直接求值),再用!!将表达式注入到当前执行环境中求值。对于默认参数cyl来说,{{x}}会先捕获cyl这个符号,再到mutate()的数据屏蔽环境中查找对应的数据列,因此不需要显式传参也能正常运行。
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

