使用 rlang 的 arg_match 检查函数输入列表

问题描述 投票:0回答:1

我正在尝试快速检查函数的参数列表,每个参数都采用严格值的向量。我一次可以做一个:

fn <- function(x = c("foo", "bar"), y = c("bar", "baz")) {
  rlang::arg_match(x)
  rlang::arg_match(y)
}

fn(x = "bar", y = "bar")
# [1] "bar"
fn(x = "baz", y = "baz")
# Error in `fn()`:
# ! `x` must be one of "foo" or "bar", not "baz".
# ℹ Did you mean "bar"?
# Run `rlang::last_trace()` to see where the error occurred.
fn(x = "bar", y = "foo")
# Error in `fn()`:
# ! `y` must be one of "bar" or "baz", not "foo".
# Run `rlang::last_trace()` to see where the error occurred.fn(x = "baz", y = "baz")

但是当我尝试将它们与 lapply 组合时,变量作为调用而不是符号传递。

fn <- function(x = c("foo", "bar"), y = c("bar", "baz")) {
  lapply(c(x, y), function(i) rlang::arg_match(enquo(i)))
}
fn(x = "bar", y = "bar")
# Error in `rlang::arg_match()`:
# ! `arg` must be a symbol, not a call.
# Run `rlang::last_trace()` to see where the error occurred.
fn <- function(x = c("foo", "bar"), y = c("bar", "baz")) {
  lapply(c("x", "y"), function(i) rlang::arg_match(get(i)))
}
fn(x = "bar", y = "bar")
# Error in `rlang::arg_match()`:
# ! `arg` must be a symbol, not a call.
# Run `rlang::last_trace()` to see where the error occurred.
fn <- function(x = c("foo", "bar"), y = c("bar", "baz")) {
  lapply(c("x", "y"), function(i) rlang::arg_match(eval(i)))
}
fn(x = "bar", y = "bar")
# Error in `rlang::arg_match()`:
# ! `arg` must be a symbol, not a call.
# Run `rlang::last_trace()` to see where the error occurred.
fn <- function(x = c("foo", "bar"), y = c("bar", "baz")) {
  lapply(c("x", "y"), function(i) rlang::arg_match({{ i }}))
}
fn(x = "bar", y = "bar")
# Error in switch(type, call = "prefix", control = , delim = , subset = "special",  :
#   EXPR must be a length 1 vector
fn <- function(x = c("foo", "bar"), y = c("bar", "baz")) {
  lapply(c(x, y), function(i) rlang::arg_match({{ i }}))
}
fn(x = "bar", y = "bar")
# Error in switch(type, call = "prefix", control = , delim = , subset = "special",  :
#   EXPR must be a length 1 vector

如何在不打电话给他们的情况下传递他们?或者是否有更有效的方法来验证参数子集每个都具有可接受的值?

r rlang
1个回答
0
投票

rlang::arg_match
base::match.arg
lapply
中都不能很好地工作,因为函数上下文发生了变化。

你可以使用 for 循环和一些 eval 废话来绕过部分

fn <- function(x = c("foo", "bar"), y = c("bar", "baz")) {
  for(v in c("x", "y")) {
    eval(rlang::expr(rlang::arg_match(!!(rlang::sym(v)))))
  }
}

或者你可以自己滚动检查器

fn <- function(x = c("foo", "bar"), y = c("bar", "baz")) {
  for(v in c("x", "y")) {
    expected <- eval(formals(sys.function())[[v]])
    if (!get(v) %in% expected) stop(paste0("'", v, "' must be one of ", toString(sQuote(expected, F)), " not '", get(v), "'"))
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.