在函数内部使用 `expr()`
Using `expr()` inside the function
Chapter 19 of Advanced R说明expr()
在函数内部没有用。
但是,在下面的例子中,如果没有 expr()
,我无法使函数工作。
假设我想在函数中对小标题进行分组。
data(iris)
iris %>% group_by(Species)
显而易见的方法是使用“curly curly”。
func_a <- function(data, grouping) {
data %>% group_by({{grouping}})
}
func_a(iris, Species)
但是,如果我允许任意提供的表达式,“curly curly”将不起作用。
func_b <- function(data, ...) {
data %>% group_by({{...}})
}
func_b(iris, Species)
# Error in (function (x) : object 'Species' not found
最后,我发现我需要 expr()
才能让它发挥作用。
func_c <- function(data, ...) {
grouping <- expr(...)
data %>% group_by(!!grouping)
}
func_c(iris, Species)
Advanced R中expr()
的例子是:
f1 <- function(x) expr(x)
f1(a + b + c)
#> x
我的主要问题是为什么 func_c
有效。 expr()
是否按原样使用 ...
并用 !!
评估它?为什么我们必须对 ...
采取不同的方法?
然后,我不确定为什么这不起作用。
func_d <- function(data, grouping) {
grouping <- expr(grouping)
data %>% group_by(!!grouping)
}
func_d(iris, Species)
我也检查了rlang manual,但是解释对我来说太简短了。
expr
阻止对代码求值。例如,尝试 运行 x
本身将失败,除非 x
是您之前声明的变量 - R 将在您评估时寻找 x
中的值它,如果没有找到这样的值,将发出错误。相比之下,expr(x)
永远不会失败(即使 x
尚未声明),因为 expr
告诉 R “只看表面价值,不要去寻找任何东西否则它可能代表”。 expr(x)
将 return 类型为“name”的东西,基本上就是一个名字。您可以将名称视为您和 R 之间的接口——它是您输入的内容,也是您传达指令的方式。 eval(expr(x))
与 x
.
相同
现在按顺序举例:
func_c <- function(data, ...) {
grouping <- expr(...)
data %>% group_by(!!grouping)
}
func_c(iris, Species)
这是有效的,因为 Species
将通过 ...
直接传递给 expr
,并且 return 类型将是一个“名称”,它存储在变量 grouping
。一个名字可以像你做的那样用 !!
求值,或者用 eval
求值。无论哪种方式,执行 !!grouping
都会导致 R 首先去寻找 grouping
变量代表的内容,找到 Species
。变量被替换为它的值,最后 !!Species
将告诉 R 去寻找名为 Species 的变量,它在 group_by
函数的上下文中将为您提供名为“Species”的列。
继续你的下一个例子:
f1 <- function(x) expr(x)
f1(a + b + c)
这不起作用只是因为 expr(x)
阻止了任何计算。 R 不会去寻找 x
里面的东西,所以它永远不会找到 a + b + c
,它需要 x
的面值,这就是你得到的。
最后,我们有你的最后一个例子:
func_d <- function(data, grouping) {
grouping <- expr(grouping)
data %>% group_by(!!grouping)
}
func_d(iris, Species)
这与您的第一个示例类似,但这里有一个额外的变量 - 名为 grouping
的参数。在您的第一个示例中,Species
直接进入函数(通过 ...
),因此它未绑定到任何参数名称。在第三个示例中,Species
通过命名参数进入函数,即绑定到变量 grouping
。然而,expr(grouping)
告诉 R“不要费心寻找 grouping
代表什么,我这里有我需要的一切”......所以它根本找不到 Species
。 expr(grouping)
只是给你名字 grouping
,不管变量本身是什么。因此,当您尝试在 group_by
中使用 !!grouping
对其进行评估时,R 会尝试查找名为 grouping
的列名称...不用说,它没有找到它,并且你得到一个 Column grouping is not found
错误。
将其视为 expr()
和 !!
有效地相互否定。
func_c <- function(data, ...) {
grouping <- expr(...)
data %>% group_by(!!grouping)
}
等同于
func_c <- function(data, ...) {
data %>% group_by(...) # Proper way to handle dots, by the way
}
(这不是完全等价的,因为前一个实现扩展了 expr
中的点,而后者扩展了 group_by
中的点。但是当单个列符号时,两种实现将产生相同的输出提供给 ...
.)
同样,
func_d <- function(data, grouping) {
grouping <- expr(grouping)
data %>% group_by(!!grouping)
}
等同于
func_d <- function(data, grouping) {
data %>% group_by(grouping) # No column `grouping` in iris
}
要使 func_d
正常工作,您需要将 expr()
替换为 enexpr()
。这将捕获提供给函数的表达式,而不是表达式 grouping
本身。
Chapter 19 of Advanced R说明expr()
在函数内部没有用。
但是,在下面的例子中,如果没有 expr()
,我无法使函数工作。
假设我想在函数中对小标题进行分组。
data(iris)
iris %>% group_by(Species)
显而易见的方法是使用“curly curly”。
func_a <- function(data, grouping) {
data %>% group_by({{grouping}})
}
func_a(iris, Species)
但是,如果我允许任意提供的表达式,“curly curly”将不起作用。
func_b <- function(data, ...) {
data %>% group_by({{...}})
}
func_b(iris, Species)
# Error in (function (x) : object 'Species' not found
最后,我发现我需要 expr()
才能让它发挥作用。
func_c <- function(data, ...) {
grouping <- expr(...)
data %>% group_by(!!grouping)
}
func_c(iris, Species)
Advanced R中expr()
的例子是:
f1 <- function(x) expr(x)
f1(a + b + c)
#> x
我的主要问题是为什么 func_c
有效。 expr()
是否按原样使用 ...
并用 !!
评估它?为什么我们必须对 ...
采取不同的方法?
然后,我不确定为什么这不起作用。
func_d <- function(data, grouping) {
grouping <- expr(grouping)
data %>% group_by(!!grouping)
}
func_d(iris, Species)
我也检查了rlang manual,但是解释对我来说太简短了。
expr
阻止对代码求值。例如,尝试 运行 x
本身将失败,除非 x
是您之前声明的变量 - R 将在您评估时寻找 x
中的值它,如果没有找到这样的值,将发出错误。相比之下,expr(x)
永远不会失败(即使 x
尚未声明),因为 expr
告诉 R “只看表面价值,不要去寻找任何东西否则它可能代表”。 expr(x)
将 return 类型为“name”的东西,基本上就是一个名字。您可以将名称视为您和 R 之间的接口——它是您输入的内容,也是您传达指令的方式。 eval(expr(x))
与 x
.
现在按顺序举例:
func_c <- function(data, ...) {
grouping <- expr(...)
data %>% group_by(!!grouping)
}
func_c(iris, Species)
这是有效的,因为 Species
将通过 ...
直接传递给 expr
,并且 return 类型将是一个“名称”,它存储在变量 grouping
。一个名字可以像你做的那样用 !!
求值,或者用 eval
求值。无论哪种方式,执行 !!grouping
都会导致 R 首先去寻找 grouping
变量代表的内容,找到 Species
。变量被替换为它的值,最后 !!Species
将告诉 R 去寻找名为 Species 的变量,它在 group_by
函数的上下文中将为您提供名为“Species”的列。
继续你的下一个例子:
f1 <- function(x) expr(x)
f1(a + b + c)
这不起作用只是因为 expr(x)
阻止了任何计算。 R 不会去寻找 x
里面的东西,所以它永远不会找到 a + b + c
,它需要 x
的面值,这就是你得到的。
最后,我们有你的最后一个例子:
func_d <- function(data, grouping) {
grouping <- expr(grouping)
data %>% group_by(!!grouping)
}
func_d(iris, Species)
这与您的第一个示例类似,但这里有一个额外的变量 - 名为 grouping
的参数。在您的第一个示例中,Species
直接进入函数(通过 ...
),因此它未绑定到任何参数名称。在第三个示例中,Species
通过命名参数进入函数,即绑定到变量 grouping
。然而,expr(grouping)
告诉 R“不要费心寻找 grouping
代表什么,我这里有我需要的一切”......所以它根本找不到 Species
。 expr(grouping)
只是给你名字 grouping
,不管变量本身是什么。因此,当您尝试在 group_by
中使用 !!grouping
对其进行评估时,R 会尝试查找名为 grouping
的列名称...不用说,它没有找到它,并且你得到一个 Column grouping is not found
错误。
将其视为 expr()
和 !!
有效地相互否定。
func_c <- function(data, ...) {
grouping <- expr(...)
data %>% group_by(!!grouping)
}
等同于
func_c <- function(data, ...) {
data %>% group_by(...) # Proper way to handle dots, by the way
}
(这不是完全等价的,因为前一个实现扩展了 expr
中的点,而后者扩展了 group_by
中的点。但是当单个列符号时,两种实现将产生相同的输出提供给 ...
.)
同样,
func_d <- function(data, grouping) {
grouping <- expr(grouping)
data %>% group_by(!!grouping)
}
等同于
func_d <- function(data, grouping) {
data %>% group_by(grouping) # No column `grouping` in iris
}
要使 func_d
正常工作,您需要将 expr()
替换为 enexpr()
。这将捕获提供给函数的表达式,而不是表达式 grouping
本身。