匿名函数中的rlang :: sym [英] rlang::sym in anonymous functions

查看:227
本文介绍了匿名函数中的rlang :: sym的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近注意到rlang::sym在匿名函数中似乎不起作用,我也不明白为什么.这里有一个例子,它很笨拙且丑陋,但我认为它说明了这一点

I recently notices that rlang::sym doesn't seem to work in anonymous functions and I don't understand why. Here an example, it's pretty clumsy and ugly but I think it illustrates the point

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的不同组合执行相同的操作:

This defines some toy data and a (horrible) function that essentially renames the columns based on column names. Now I can do the same thing for different combinations of a and b:

d <- tibble(x = c("x1", "x2"),
            y = c("x2", "x1"))
d %>% mutate(tmp = map2(x, y, get_it))

但是,如果我尝试使用匿名函数做完全相同的事情,那将是行不通的:

However, if I try to do the exact same thing with an anonymous function it doesn't work:

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进行操作,即使函数完全相同(在此处是匿名的)也是如此.谁能解释为什么?

This fails with object 'a' not found even though the functions are exactly the same just here it is anonymous. Can anyone explain why?

推荐答案

问题不是匿名函数,而是!!的运算符优先级. !!的帮助页面指出

The issue is not anonymous functions, but the operator precedence of !!. The help page for !! states that

!!运算符取消引用其参数.在周围的环境中立即对其进行评估.

这意味着当您在mutate内编写复杂的NSE表达式时,例如select,取消引用将在整个表达式的环境中发生.正如@lionel指出的那样,取消引号优先于其他事情,例如创建匿名函数环境.

This implies that when you write a complex NSE expression, such as select inside mutate, the unquoting will take place in the environment of the expression as a whole. As pointed out by @lionel, the unquoting then takes precedence over other things, such as creation of anonymous function environments.

在您的情况下,对外部mutate()!!取消引用,然后尝试在d而不是data内查找列x1.有两种可能的解决方案:

In your case the !! unquoting is done with respect to the outer mutate(), which then attempts to find column x1 inside d, not data. There are two possible solutions:

1)将涉及!!的表达式放入独立函数中(如您在问题中所做的那样):

1) Pull the expression involving !! into a standalone function (as you've done in your question):

res1 <- d %>% mutate(tmp = map2(x, y, get_it))

2)将!!替换为eval以延迟表达式求值:

2) Replace !! with eval to delay expression evaluation:

res2 <- d %>% mutate(tmp = map2(x, y, function(a, b){
  data %>%
    mutate(y1 = eval(rlang::sym(a))) %>%
    mutate(y2 = eval(rlang::sym(b))) %>%
    select(y1, y2, val)
}))

identical(res1, res2)       #TRUE

这篇关于匿名函数中的rlang :: sym的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆