【发布时间】:2019-01-24 21:54:02
【问题描述】:
我最近注意到rlang::sym 似乎不适用于匿名函数,我不明白为什么。这是一个例子,它非常笨拙和丑陋,但我认为它说明了这一点
require(tidyverse)
data <- tibble(x1 = letters[1:3],
x2 = letters[4:6],
val = 1:3)
get_it <- function(a, b){
data %>%
mutate(y1 = !!rlang::sym(a)) %>%
mutate(y2 = !!rlang::sym(b)) %>%
select(y1, y2, val)
}
get_it("x1", "x2")
这定义了一些玩具数据和一个(可怕的)函数,该函数本质上是根据列名重命名列。现在我可以对 a 和 b 的不同组合做同样的事情:
d <- tibble(x = c("x1", "x2"),
y = c("x2", "x1"))
d %>% mutate(tmp = map2(x, y, get_it))
但是,如果我尝试对匿名函数执行完全相同的操作,则它不起作用:
d %>% mutate(tmp = map2(x, y, function(a, b){
data %>%
mutate(y1 = !!rlang::sym(a)) %>%
mutate(y2 = !!rlang::sym(b)) %>%
select(y1, y2, val)
}))
即使功能完全相同,object 'a' not found 也会失败,只是这里是匿名的。谁能解释一下为什么?
【问题讨论】:
-
嗯,真正的益智游戏。我认为这一定与定义函数的环境有关,但无法区分...
-
这可能不是错误,但我会在 Git 上将其报告为问题。
-
如果我们消除这里实际上不需要的 rlang,那么它就可以工作:
function(a, b) data %>% mutate(y1 = .[[a]], y2 = .[[b]]) %>% select(y1, y2, val)所以看起来匿名函数可以工作,但其中不包含 rlang。 -
取消引用不是函数调用:它总是在第一个最外面的引用函数处生效。这就是为什么您必须小心使用匿名函数的原因。取消引用会立即发生,而匿名函数表示稍后创建的范围,因此存在时间问题。
-
这是我们决定弃用
UQ()和UQS()的原因之一,尽管它们的语义非常不同,但它们看起来太像函数调用了。