将 curly-curly (`{{ }}`) 运算符与 `if` 子句一起使用时出错
Error when using curly-curly (`{{ }}`) operator with `if` clause
我正在努力理解如何使用 {{ }}
运算符在自定义函数中传递裸变量名。当我将运算符与 if
子句结合使用时出现错误。
此功能有效:
f <- function(.data, .vars=NULL){
require(dplyr)
df = select(.data, {{ .vars }})
print(head(df))
}
f(iris, c(Species, Sepal.Length))
#> Loading required package: dplyr
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
#> Species Sepal.Length
#> 1 setosa 5.1
#> 2 setosa 4.9
#> 3 setosa 4.7
#> 4 setosa 4.6
#> 5 setosa 5.0
#> 6 setosa 5.4
由 reprex package (v2.0.1)
于 2021-12-20 创建
如果我尝试添加 if
子句,它会抛出错误:
f <- function(.data, .vars=NULL){
require(dplyr)
if(!is.null(.vars)) df = select(.data, {{ .vars }})
else df = .data
print(head(df))
}
f(iris, c(Species, Sepal.Length))
#> Loading required package: dplyr
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
#> Error in f(iris, c(Species, Sepal.Length)): object 'Species' not found
由 reprex package (v2.0.1)
于 2021-12-20 创建
我错过了什么?
我认为最简单的解释是,当 .vars
不是 NULL
时,R 会将值(在您的示例中:c(Species, Sepal.Length)
)解释为变量向量,并查看对于您环境中的这些变量。由于您没有任何名为 Species
的变量,它会引发错误。
你可以这样修复:
library(dplyr)
f <- function(.data, .vars = NULL){
vars <- enquo(.vars)
if(!rlang::quo_is_null(vars)) df = select(.data, !!vars)
else df = .data
print(head(df))
}
f(iris)
f(iris, c(Species, Sepal.Length))
请注意 {{x}}
实际上是 !!enquo(x)
的 shorthand。
详细说明(更新)
当您不使用 if
时,唯一使用 .vars
的地方是在 dplyr::select(.data, {{.vars}})
内。在这种情况下,.vars
中的变量名称被解释为数据帧 .data
.
中的变量
当您添加 if
语句时,.vars
被评估为您环境中的变量。由于它们不存在于您的环境中,因此您会收到错误消息。
这称为数据屏蔽。
Here 是一个
关于它的好文章。
@jpiversen 的回答和解释是正确的,但这里有一个更简单的函数修复方法。不要寻找 NULL
的默认值,只需检查 .vars
是否丢失:
library(dplyr)
f <- function(.data, .vars){
if(!missing(.vars)) df = select(.data, {{ .vars }})
else df = .data
print(head(df))
}
f(iris, c(Species, Sepal.Length))
顺便说一下,我还从你的函数中删除了 require(dplyr)
。在函数中使用它通常不是一个好主意,因为更改搜索列表会产生副作用。如果您不确定它是否可用,请使用 requireNamespace("dplyr")
并使用 dplyr::
作为前缀函数。
我正在努力理解如何使用 {{ }}
运算符在自定义函数中传递裸变量名。当我将运算符与 if
子句结合使用时出现错误。
此功能有效:
f <- function(.data, .vars=NULL){
require(dplyr)
df = select(.data, {{ .vars }})
print(head(df))
}
f(iris, c(Species, Sepal.Length))
#> Loading required package: dplyr
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
#> Species Sepal.Length
#> 1 setosa 5.1
#> 2 setosa 4.9
#> 3 setosa 4.7
#> 4 setosa 4.6
#> 5 setosa 5.0
#> 6 setosa 5.4
由 reprex package (v2.0.1)
于 2021-12-20 创建如果我尝试添加 if
子句,它会抛出错误:
f <- function(.data, .vars=NULL){
require(dplyr)
if(!is.null(.vars)) df = select(.data, {{ .vars }})
else df = .data
print(head(df))
}
f(iris, c(Species, Sepal.Length))
#> Loading required package: dplyr
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
#> Error in f(iris, c(Species, Sepal.Length)): object 'Species' not found
由 reprex package (v2.0.1)
于 2021-12-20 创建我错过了什么?
我认为最简单的解释是,当 .vars
不是 NULL
时,R 会将值(在您的示例中:c(Species, Sepal.Length)
)解释为变量向量,并查看对于您环境中的这些变量。由于您没有任何名为 Species
的变量,它会引发错误。
你可以这样修复:
library(dplyr)
f <- function(.data, .vars = NULL){
vars <- enquo(.vars)
if(!rlang::quo_is_null(vars)) df = select(.data, !!vars)
else df = .data
print(head(df))
}
f(iris)
f(iris, c(Species, Sepal.Length))
请注意 {{x}}
实际上是 !!enquo(x)
的 shorthand。
详细说明(更新)
当您不使用
中的变量if
时,唯一使用.vars
的地方是在dplyr::select(.data, {{.vars}})
内。在这种情况下,.vars
中的变量名称被解释为数据帧.data
.当您添加
if
语句时,.vars
被评估为您环境中的变量。由于它们不存在于您的环境中,因此您会收到错误消息。
这称为数据屏蔽。 Here 是一个 关于它的好文章。
@jpiversen 的回答和解释是正确的,但这里有一个更简单的函数修复方法。不要寻找 NULL
的默认值,只需检查 .vars
是否丢失:
library(dplyr)
f <- function(.data, .vars){
if(!missing(.vars)) df = select(.data, {{ .vars }})
else df = .data
print(head(df))
}
f(iris, c(Species, Sepal.Length))
顺便说一下,我还从你的函数中删除了 require(dplyr)
。在函数中使用它通常不是一个好主意,因为更改搜索列表会产生副作用。如果您不确定它是否可用,请使用 requireNamespace("dplyr")
并使用 dplyr::
作为前缀函数。