R语言中参数默认值设为NULL时调用报错的原因解析
问题描述
我尝试编写一个将部分参数默认值设为NULL的R函数,但调用时指定这些参数(传入数据框列名)却收到‘对象未找到’的错误。
示例初始函数
library(dplyr) toydf <- data.frame(Name = "Fred", Age="Old", Hair="Brown") toyA <- function(df, groupA){ data.frame(A = df%>%dplyr::select({{groupA}})) } toyA(toydf, Name) toyA(toydf, Age)
尝试的NULL默认值函数(toyB)
参考资料显示可将参数默认值设为NULL,于是编写函数toyB:
toyB <- function(df, groupA, groupB=NULL, groupC=NULL){ if((!is.null(groupB)) & (!is.null(groupC))){ data.frame(A = df%>%dplyr::select({{groupA}}), B = df%>%dplyr::select({{groupB}}), C = df%>%dplyr::select({{groupC}})) } else{ data.frame(A = df%>%dplyr::select({{groupA}})) } }
调用toyB(toydf, Name, Age, Hair)时出现错误:
Error in toyB(toydf, Name, Age, Hair) : object 'Age' not found
可正常运行的missing()版本(toyC)
使用missing()函数的toyC可正常运行:
toyC <- function(df, groupA, groupB, groupC){ if((!missing(groupB)) & (!missing(groupC))){ data.frame(A = df%>%dplyr::select({{groupA}}), B = df%>%dplyr::select({{groupB}}), C = df%>%dplyr::select({{groupC}})) } else{ data.frame(A = df%>%dplyr::select({{groupA}})) } } toyC(toydf,Name) toyC(toydf, Name, Age, Hair)
请问为何参数默认值设为NULL的方式无法正常工作?
问题原因
核心问题出在参数的求值时机上:
- 当给参数设置
groupB=NULL这类默认值时,R会在函数调用阶段就尝试对传入的实参(比如Age)进行求值。但Age只是数据框toydf里的列名,不是全局环境中的独立对象,所以会抛出“对象未找到”的错误。 - 而
missing()函数的逻辑是检查参数是否被显式传入,它不会提前去求值实参。配合{{ }}(rlang的非标准求值语法),{{groupB}}会延迟到dplyr::select内部才去数据框的环境里解析列名,这就避开了全局环境中找不到对象的问题。
简单来说:默认值为NULL时,R先找全局环境里的Age,找不到就报错;用missing()时,R先不管Age是什么,等进入select时再去数据框里找对应的列,自然没问题。
修正方案
如果想保留默认值为NULL的写法,需要用rlang::enquo()捕获表达式,延迟实参的求值时机,让解析过程在数据框环境中进行。修改后的toyB如下:
toyB_fixed <- function(df, groupA, groupB=NULL, groupC=NULL){ # 用enquo捕获表达式,避免提前求值 groupB <- rlang::enquo(groupB) groupC <- rlang::enquo(groupC) if((!rlang::quo_is_null(groupB)) & (!rlang::quo_is_null(groupC))){ data.frame( A = df%>%dplyr::select({{groupA}}), B = df%>%dplyr::select(!!groupB), C = df%>%dplyr::select(!!groupC) ) } else { data.frame(A = df%>%dplyr::select({{groupA}})) } }
调用toyB_fixed(toydf, Name, Age, Hair)就能正常运行,因为enquo捕获了Age这个表达式,没有提前求值,直到!!(解引用操作符)时才在df的环境里解析对应的列名。
内容的提问来源于stack exchange,提问作者Reid
相关产品推荐
相关产品推荐

