非标准评估(NSE)经常与tidyverse/dplyr一起使用,但大多数人在加载软件包时每天都会遇到它。
a <- "rlang"
print(a) # Standard evaluation: the expression a is replace by its value
# [1] "rlang"
library(a) # Non-standard evaluation: the expression a is used as-is
# Error in library(a) : there is no package called ‘a’
那么,如何加载动态指定的软件包?这里,我们将使用引用语法进行演示。(在实际代码中,我建议改为library(a, character.only=TRUE)
。)
在基础 R 中,您可以使用 bquote()
动态构造一个表达式并对其求值。
myexpr <- bquote(library(.(a)))
eval(myexpr)
rlang
提供了额外的工具来操作表达式。通常,它们比基础 R 工具更加灵活。 !!
的行为与上述类似:
myexpr <- rlang::expr(library(!!a))
您可以使用rlang::expr
和!!
来构建任何表达式以供未来评估。
x <- rlang::expr(mtcars)
y <- rlang::expr(mpg > 30)
z <- rlang::expr(disp)
rlang::expr(subset(!!x, !!y, !!z))
当你有很多参数时,你可以把它们放在一个列表中并使用!!!
快捷方式。上面的表达式可以用以下方式复制:
l <- rlang::exprs(mtcars, mpg > 30, disp) # Note the s on exprs
rlang::expr(subset(!!!l)) # Also builds subset(mtcars, mpg > 30, disp)
{{
运算符是最难解释的一种运算符,需要先介绍quo引用。
R语言中的表达式是一等对象,这意味着它们可以作为参数传递给函数、被函数返回等等。但是,使用rlang::expr
创建的表达式总是在其即时上下文中进行评估。考虑以下代码:
a <- 10
x <- rlang::expr(a+5)
f <- function(y) {
a <- 5
eval(y)
}
f(x)
尽管表达式
x
捕获了
a+5
,但在评估表达式之前,变量
a
的值已发生更改。Quosure会捕捉表达式和定义它们的环境,该环境始终用于评估该表达式。
a <- 10
x <- rlang::quo(a+5)
f <- function(y) {
a <- 5
eval_tidy(y)
}
f(x)
通过使用expr
和quo
的en-
版本,可以将表达式或引用捕获并移动到函数内部:
f <- function(y) {
a <- 5
eval(rlang::enexpr(y))
}
g <- function(y) {
a <- 5
eval_tidy(rlang::enquo(y))
}
允许用户直接将表达式传递给函数
a <- 10
f(a*4)
g(a*4)
综上所述,{{x}}
只是!!enquo(x)
的简写。
!!
表示对 "逻辑运算符" 进行双重否定(!!!
表示三重否定)。而rlang
和其他 tidyverse 包则采用了该符号来进行非标准评估变量的操作。 - r2evans