我最近注意到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
的功能完全相同(此处只是匿名),也会失败。谁能解释为什么?
答案 0 :(得分:7)
请注意,以下代码在匿名函数中具有#NoTrayIcon
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
SetWidth = 1616
SetHeight = 939
Run, ".\full throttle remastered.bat"
Process, Wait, throttle.exe, 120
Process, Exist, throttle.exe
Throttle = %ErrorLevel%
if Throttle != 0
{
Sleep, 2000
CenterWindow("ahk_exe throttle.exe")
}
else
{
MsgBox "Full Throttle Remastered could not be started"
}
return
; The following function centers the specified window on the screen if not already centered:
CenterWindow(WinTitle)
{
WinGetPos,xx,yy, winx, winy, %WinTitle%
x1 := xx + winx/2
y1 := yy + winy/2
loop 2
{
y1 := yy + winy/2
loop 2
{
if ((A_ScreenWidth/2 = x1) && (A_ScreenHeight/2 = y1) && (winx = %SetWidth%) && (winy = %SetHeight%))
{
msgbox got em
return
}
else
y1 := y1 + 0.5
}
x1 := x1 + 0.5
}
WinMove, ahk_exe throttle.exe,, 0, 0, %SetWidth%, %SetHeight%
WinGetPos,,, winx, winy, %WinTitle%
Sleep, 100
WinMove, %WinTitle%,, (A_ScreenWidth/2)-(winx/2), (A_ScreenHeight/2)-(winy/2)
}
return
,并且可以正常工作:
rlang::sym()
原始问题与取消引用运算符map2(c("x1","x2"), c("x2","x1"), function(a, b){
data %>%
mutate(y1 = !!rlang::sym(a)) %>%
mutate(y2 = !!rlang::sym(b)) %>%
select(y1, y2, val)})
及其相对于非标准评估(NSE)函数(例如!!
中的匿名函数创建的优先级)有关。考虑嵌套数据框
mutate
如果我尝试使用以下方法在每个内部数据框中选择第一列
XX <- data_frame( dfs = list(
data_frame( x = letters[1:3], y = 1:3 ),
data_frame( x = letters[4:6], y = 4:6 )) )
我收到一个XX %>% mutate( dfs1 = map( dfs, function(df) {
i <- 1
df %>% select(!!i)} ))
错误,因为在创建匿名函数(包含object 'i' not found
)的环境之前,!!
的取消引用相对于外部mutate
发生了。如果我将匿名函数移到select
mutate
它可以正常工作,因为map( XX$dfs, function(df) {
i <- 1
df %>% select(!!i)} )
遵循标准的评估规则,并且现在在取消引用之前创建了匿名函数环境。
map
的帮助页面指出
!!运算符取消引用其参数。它会在周围环境中立即得到评估。
这意味着当您在!!
内编写复杂的NSE表达式时,例如select
,取消引用将在整个表达式的环境中发生。正如@lionel在评论中指出的那样,NSE中的取消引用优先于其他事情,例如创建匿名函数环境。