为什么在传递给 tidyr ... 参数时需要将返回字符向量的函数包装到 c() 中?

Why do I need to wrap function returning a character vector into c() when passing to tidyr ... argument?

参见示例:

df <- data.frame(month=rep(1:3,2),
                 student=rep(c("Amy", "Bob"), each=3),
                 A=c(9, 7, 6, 8, 6, 9),
                 B=c(6, 7, 8, 5, 6, 7))
cnames<-function(){c(month="month",student="student")}

cnames() 包装到 c() 时,对 tidyr::gather 的调用有效:

df2 <- df %>% 
  gather(variable, value, -c(cnames()))

但是当我用 cnames() 甚至 (cnames()) 调用它时它失败了 :

df2 <- df %>% 
  gather(variable, value, -(cnames()))

> df2 <- df %>% 
+   gather(variable, value, -(cnames()))
Error in -(cnames()) : invalid argument to unary operator

我猜这与 NSE 有关,但具体是什么?

我相信 'proper' 当前 tidyverse/tidyselect 的做法是...

df %>% gather(variable, value, -(!! cnames()))

df %>% gather(variable, value, -c(cnames())) 起作用的原因是因为 c()tidyselect 中的处理方式与平常不同。参见 string coercion affects c() #37

df %>% gather(variable, value, -(cnames())) not 工作因为整个表达式求值(包括 -),所以你会得到与 [=30 相同的错误=] 简单地 -(cnames())