我偶然发现了这种行为,并不太了解。有人可以照亮一下吗?
我编写了以下函数,该函数给出以下错误:
let tokenSoundTrack;
function sound() {
tokenSoundTrack = 4;
}
function sound2() {
tokenSoundTrack = 2;
}
但是,如果我以以下方式对其进行修改,则它会按预期工作:
> MyFilter <- function(data, filtersVector) {
filtersVector <- quo(filtersVector)
result <- data %>% filter(Species %in% !!filtersVector)
result
}
> MyFilter(iris, c("setosa", "virginica"))
Error in filter_impl(.data, quo) :
Evaluation error: 'match' requires vector arguments.
我也意识到,在一个函数中,我应该改用> MyFilter <- function(data, filtersVector) {
otherName <- quo(filtersVector)
result <- data %>% filter(Species %in% !!otherName)
result
}
> MyFilter(iris, c("setosa", "virginica"))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
,它可以正常工作。
enqou
但是,我仍然对上述行为感到困惑,将不胜感激。
答案 0 :(得分:5)
TLDR:在第一个版本中,您已经创建了一个自引用(一个指向自身的符号)。其他版本也可以使用,但是实际上您不需要在这里使用quasure和捕获参数,因为您没有在引用数据框列。这也解释了为什么quo()
和enquo()
版本都工作相同的原因。您可以按常规方式传递参数,而不用引号,尽管用!!
取消引号仍然是一个好主意,以避免任何数据掩盖错误。
您可以在qq_show()
调用周围使用filter()
来发现语法差异:
MyFilter <- function(data, filtersVector) {
filtersVector <- quo(filtersVector)
rlang::qq_show(
result <- data %>% filter(Species %in% !!filtersVector)
)
}
MyFilter(iris, c("setosa", "virginica"))
#> result <- data %>% filter(Species %in% (^filtersVector))
因此,我们在这里要求filter()
查找其中Species
与filtersVector
的元素匹配的行。数据框中没有filtersVector
列,因此它在quosure环境中寻找定义。您已使用quo()
创建了一个quosure,它记录了您的表达式(在本例中为符号filtersVector
)和您的环境(您的环境功能)。因此,它将查找filtersVector
对象,该对象包含一个指向自身的符号。它仅被评估一次,因此没有无限循环,但是您实际上正在尝试将向量与符号进行比较,这是类型错误:
"setosa" %in% quote(filtersVector)
#> Error in match(x, table, nomatch = 0L) :
#> 'match' requires vector arguments
在第二次尝试中,您给quasure取了另一个名字。由于filtersVector
在您的函数环境中仍然代表传递给它的参数(向量),因此现在可以使用。
在第三次尝试中,您这次使用enquo()
。 enquo()
并非捕获您的表达式和您的环境,而是捕获了函数用户的表达式和环境。让我们再次使用qq_show()
来了解不同之处:
MyFilter <- function(data, filtersVector) {
filtersVector<- enquo(filtersVector)
rlang::qq_show(
data %>% filter(Species %in% !!filtersVector)
)
}
MyFilter(iris, c("setosa", "virginica"))
#> data %>% filter(Species %in% (^c("setosa", "virginica")))
现在,quoquo包含一个在现场创建矢量的调用,%in%
非常清楚。
请注意,您实际上不是在实际上指数据框列。您正在传递矢量。这意味着您根本不需要任何保证,也不需要捕获传递给参数的表达式。 enquo()
仅对 delay 评估直到最后都有用,因此可以在数据框中进行评估。如果quo()
和enquo()
版本产生相同的结果,则表明您根本不需要引用。由于不需要它们,因此让我们通过消除方程的简化来简化函数:
MyFilter <- function(data, filtersVector) {
data %>% filter(Species %in% filtersVector)
}
MyFilter(iris, c("setosa", "virginica"))
#> # A tibble: 100 x 5
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> <dbl> <dbl> <dbl> <dbl> <fct>
#> 1 5.1 3.5 1.4 0.2 setosa
#> 2 4.9 3 1.4 0.2 setosa
#> 3 4.7 3.2 1.3 0.2 setosa
#> 4 4.6 3.1 1.5 0.2 setosa
#> 5 5 3.6 1.4 0.2 setosa
#> 6 5.4 3.9 1.7 0.4 setosa
#> 7 4.6 3.4 1.4 0.3 setosa
#> 8 5 3.4 1.5 0.2 setosa
#> 9 4.4 2.9 1.4 0.2 setosa
#> 10 4.9 3.1 1.5 0.1 setosa
#> # ... with 90 more rows
有效!但是,如果数据帧包含filtersVector
列会怎样?它优先于环境中的对象:
iris %>%
mutate(filtersVector = "parasite vector") %>%
MyFilter(c("setosa", "virginica"))
#> # A tibble: 0 x 6
#> # ... with 6 variables: Sepal.Length <dbl>, Sepal.Width <dbl>,
#> # Petal.Length <dbl>, Petal.Width <dbl>, Species <fct>, filtersVector <chr>
所以取消引用仍然是一个好主意,因为这将立即评估向量并将其粘贴在过滤器表达式中。它不能再被列掩盖。内联由qq_show()
显示:
MyFilter <- function(data, filtersVector) {
rlang::qq_show(
data %>% filter(Species %in% !!filtersVector)
)
}
MyFilter(iris2, c("setosa", "virginica"))
#> data %>% filter(Species %in% <chr: "setosa", "virginica">)
答案 1 :(得分:1)
当我们传递带引号的向量字符串而不是未引用的字符串时,我们需要使用syms
中的rlang
MyFilter <- function(data, filtersVector) {
filtersVector <- rlang::syms(filtersVector)
data %>%
filter(Species %in% !!filtersVector)
}
out <- MyFilter(iris, c("setosa", "virginica"))
dim(out)
#[1] 100 5