我有一个大致遵循这种结构的功能:
TestFunc <- function(dat, point) {
if (!(point %in% c("NW", "SE", "SW")))
stop("point must be one of 'SW', 'SE', 'NW'")
point <- enquo(point)
return(dat %>% filter(point == !!point))
问题是,当我包含值检查时,我收到以下错误:
Error in (function (x, strict = TRUE) :
the argument has already been evaluated
删除支票后错误消失。我怎么能保留两者?
答案 0 :(得分:2)
关于quosure框架需要记住的是,它是一个非常聪明,复杂的代码片段,它可以撤消另一个非常聪明,复杂的代码,让你回到起点。你想要的是以一种非常简单的方式实现,而不需要去NSE再回来。
TestFunc <- function(dat, point)
{
if(!(point %in% c("NW", "SE", "SW")))
stop("point must be one of 'SW', 'SE', 'NW'")
dat[dat$point == point, ]
}
(正如@Frank在评论中建议的那样,使用match.arg
之间的差异是match.arg
如果没有提供输入,则会使用第一个值作为默认值,而这将失败。)
如果你想调用其他dplyr / tidyverse动词,只需在过滤行后再这样做。
答案 1 :(得分:1)
由于技术原因与R优化代码的方式有关,您只能捕获尚未评估的参数。
首先必须使用enquo()
进行捕获,然后继续检查值。但是,如果必须混合引用和基于值的代码,则通常表明存在设计问题。
正如Hong所说,在你的情况下,你可以直接取消引用该值而不捕获它。 Unquoting将确保找到正确的值(因为您为该变量指定了与数据框中的列相同的名称)。
答案 2 :(得分:0)
point
以便filter
可以区分参数和数据列aosmith有一个好主意,所以我将它放在答案中,并附上一个可重现的例子:
f <- function(dat, point) {
if (!(point %in% c("NW", "SE", "SW")))
stop("point must be one of 'SW', 'SE', 'NW'")
filter(dat, point == !!point)
}
tbl <- tibble(point = c('SE', 'NW'))
f(tbl, 'SE')
f(tbl, 'XX')
如果您以字符串形式传递point
,则只需要区分参数point
(=&#34; SE&#34;,在本例中)和列dat$point
(或tbl$point
,视您是否在函数内部或外部而定。来自dplyr programming doc:
在dplyr(和一般的tidyeval)你用!!要说你想要取消引用一个输入,以便它被评估,而不是引用。
您想要评估参数point
,以便&#34; SE&#34;传递给filter
,这样filter
可以区分列point
和参数SE
。
(我也尝试使用filter(dat, .data$point == point)
,但RHS point
仍然引用了列,而不是f
参数。)
我希望这个例子可以帮助您实现真正的代码。