我正在编写一个接受可变数量参数的函数.此外,我希望用户能够将这些参数中的一些遗漏.
考虑将...变成参数列表的任务.这是我的第一次尝试:
f <- function(...) list(...)
Run Code Online (Sandbox Code Playgroud)
这失败了:
f(1,,2)
## Error in f(1, , 2) : argument is missing, with no default
Run Code Online (Sandbox Code Playgroud)
我希望结果如此list(1, NULL, 2).(我并不担心区分f(1,,2)从f(1,NULL,2).)
这是我的第二次尝试:
g <- function(...)
{
args <- match.call()
miss <- vapply(args, identical, NA, quote(expr=))
args[miss] <- list(NULL)
args[[1L]] <- quote(list)
eval.parent(args)
}
Run Code Online (Sandbox Code Playgroud)
这工作(有点):
identical(g(1,,2), list(1, NULL, 2))
## [1] TRUE
Run Code Online (Sandbox Code Playgroud)
但是,转发点时失败:
gg <- function(...) g(...)
identical(gg(1,,2), list(1,NULL,2))
## [1] FALSE
Run Code Online (Sandbox Code Playgroud)
有没有办法实现相同的结果g,但在某种方式允许转发点而不使用match.call()?
尝试以下方法很有诱惑力:
h <- function(...)
{
args <- substitute(list(...))
miss <- vapply(args, identical, NA, quote(expr=))
args[miss] <- list(NULL)
eval.parent(args)
}
Run Code Online (Sandbox Code Playgroud)
但是,正如@lionel指出的那样,如果您尝试...从另一个函数转发,则会出现问题:
hh <- function(...) h(letters, ...)
local({ a <- "foo"; h(a) })
## Error in eval(expr, p) : object 'a' not found
Run Code Online (Sandbox Code Playgroud)
看起来你要么需要expand.dots功能match.call,要么需要使用quosure(来自rlang包).
使用rlang包,您可以选择在捕获点时忽略空参数:
my_dots <- function(...) {
rlang::dots_list(..., .ignore_empty = "all")
}
my_dots(1, , 2, )
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 2
Run Code Online (Sandbox Code Playgroud)
如果你真的需要翻译空参数,NULL除了引用点并在转换缺失参数后评估它们之外别无选择.现在,如果您这样做,eval(substitute(alist(...))如果您尝试通过多个函数调用转发点,则会遇到麻烦.Base R无法在原始环境中评估引用的参数.
幸运的是,通过捕获quosures中的点可以很容易地做到:
library("purrr") # For convenient map_if()
my_dots <- function(...) {
quos <- rlang::quos(..., .ignore_empty = "none")
quos <- map_if(quos, rlang::quo_is_missing, function(x) NULL)
map(quos, rlang::eval_tidy)
}
my_dots(1, , 2, )
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> NULL
#>
#> [[3]]
#> [1] 2
#>
#> [[4]]
#> NULL
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
177 次 |
| 最近记录: |