更新时间:2023-11-08 22:01:46
这确实不是一件容易的事.如果要构建函数,则可以使用 match.call
捕获呼叫,可以轻松解析该呼叫:
This is really not an easy thing to do. If you're building the function, you can capture the call with match.call
, which can be parsed without too much trouble:
f <- function(x, y = 1, ...){
cl <- match.call()
as.list(cl[-1])
}
str(f(1))
#> List of 1
#> $ x: num 1
str(f(1, 'foo'))
#> List of 2
#> $ x: num 1
#> $ y: chr "foo"
str(f(1, 'foo', list(3), fun = sum))
#> List of 4
#> $ x : num 1
#> $ y : chr "foo"
#> $ : language list(3)
#> $ fun: symbol sum
注意 match.call
仅捕获呼叫,并且不添加默认参数(在第一个示例中没有 y
).可以使用 formals(f)
来访问它们,因为 f
不是原始的,因此可以通过
Note match.call
only captures the call, and doesn't add in default parameters (there's no y
in the first example). Those can be accessed with formals(f)
, since f
isn't primitive, so complete arguments could be created via
user_args <- f(1)
fun_args <- formals(f)
fun_args[names(user_args)] <- user_args
str(fun_args)
#> List of 3
#> $ x : num 1
#> $ y : num 1
#> $ ...: symbol
这种方法不适用于完成的点,但是如果它们完成了,则 match.call
本身就足够了.要提取传递给现有函数的参数,可以使用 match.call
编写包装,但是重构每个函数几乎是不实际的,除非您覆盖现有函数,否则捕获的调用无论如何都会看起来很有趣..只要该函数不是原始函数,就可以使用 quote
启用 formals
方法,
This approach doesn't work well for completed dots, but if they're completed then match.call
itself should suffice. To extract the parameters passed to an existing function, you could write a wrapper with match.call
, but it's hardly practical to reconstruct every function, and the call you capture will look funny anyway unless you overwrite existing functions. As long as the function isn't primitive, you could use quote
to enable the formals
approach, though:
cl <- quote(rnorm(5, 2))
user_args <- as.list(cl[-1]) # subset call to only args
fun_args <- formals(as.character(cl[1])) # subset call to only function
names(user_args) <- names(fun_args)[seq(length(user_args))]
fun_args[names(user_args)] <- user_args
str(fun_args)
#> List of 3
#> $ n : num 5
#> $ mean: num 2
#> $ sd : num 1
另一种方法是使用rlang,其功能可以很好地处理原语( fn_fmls(sum)
),可以轻松而可靠地提取部分调用( lang_fn
, lang_args
),准确命名未命名的参数( lang_standardize
)等.连同purrr的新 list_modify
(开发版)一起,这一切都变得很轻松:
Another approach is to use rlang, whose functions handle primitives well (fn_fmls(sum)
), can extract parts of the call easily and reliably (lang_fn
, lang_args
), name unnamed parameters accurately (lang_standardize
), and more. Together with purrr's new list_modify
(dev version), it all becomes fairly painless:
library(rlang)
fun_call <- quo(rnorm(5))
fun_call
#> <quosure: frame>
#> ~rnorm(5)
default_args <- fn_fmls(lang_fn(fun_call))
str(default_args)
#> Dotted pair list of 3
#> $ n : symbol
#> $ mean: num 0
#> $ sd : num 1
user_args <- lang_args(lang_standardise(fun_call))
str(user_args)
#> List of 1
#> $ n: num 5
calling_args <- purrr::list_modify(default_args, user_args)
str(calling_args)
#> Dotted pair list of 3
#> $ n : num 5
#> $ mean: num 0
#> $ sd : num 1