You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用rlang的arg_match批量检查R函数的输入参数?

批量验证R函数参数取值合法性的方法

我需要快速检查函数中多个只能取特定值的参数,逐个调用rlang::arg_match可以实现需求:

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.

但尝试用lapply批量处理时,变量会被当作调用而非符号传入,出现报错:

# 错误尝试1:传入参数值而非符号
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.

# 错误尝试2:用get获取参数值
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.

# 错误尝试3:用eval获取参数值
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.

# 错误尝试4:用{{}}拼接符号
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

# 错误尝试5:传入参数值用{{}}
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

正确的批量处理方法

rlang::arg_match需要接收符号而非参数值或调用表达式,以下是几种可行的批量验证方案:

方法1:用rlang::sym()转换字符串为符号

通过字符串参数名转换为符号,配合非标准求值传递给arg_match,保留原生报错提示:

library(rlang)

fn <- function(x = c("foo", "bar"), y = c("bar", "baz")) {
  # 定义参数名与对应可选值的映射
  arg_options <- list(
    x = c("foo", "bar"),
    y = c("bar", "baz")
  )
  
  # 遍历参数名批量验证
  lapply(names(arg_options), function(arg_name) {
    arg_sym <- sym(arg_name)
    arg_match(!!arg_sym, values = arg_options[[arg_name]])
  })
  
  # 返回处理后的参数(可选)
  list(x = x, y = y)
}

fn(x = "bar", y = "bar")
# $x
# [1] "bar"
# $y
# [1] "bar"

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

方法2:使用rlang::arg_match0()更高效

arg_match0()无需传入符号,直接接收参数值和可选值,更适合批量场景,还能手动指定报错中的参数名:

library(rlang)

fn <- function(x = c("foo", "bar"), y = c("bar", "baz")) {
  arg_list <- list(x = x, y = y)
  arg_options <- list(
    x = c("foo", "bar"),
    y = c("bar", "baz")
  )
  
  # 批量匹配验证
  mapply(function(val, opts, arg_name) {
    arg_match0(val, opts, arg = arg_name)
  }, arg_list, arg_options, names(arg_list))
  
  list(x = x, y = y)
}

fn(x = "bar", y = "foo")
# Error in `arg_match0()`:
# ! `y` must be one of "bar" or "baz", not "foo".
# Run `rlang::last_trace()` to see where the error occurred.

方法3:base R原生方案match.arg()

如果不想依赖rlang包,可使用base R的match.arg()实现批量验证:

fn <- function(x = c("foo", "bar"), y = c("bar", "baz")) {
  arg_list <- list(x = x, y = y)
  arg_options <- list(
    x = c("foo", "bar"),
    y = c("bar", "baz")
  )
  
  # 批量匹配验证
  mapply(function(val, opts) {
    match.arg(val, opts)
  }, arg_list, arg_options)
  
  list(x = x, y = y)
}

fn(x = "baz", y = "baz")
# Error in match.arg(val, opts) : 
#   'arg' should be one of "foo", "bar"

内容的提问来源于stack exchange,提问作者dragon951

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 18:25:31