【问题标题】:忽略省略号函数中的参数丢失错误
【发布时间】:2023-04-03 17:05:02
【问题描述】:

以下代码产生Error: argument is missing, with no default,因为来自调用者的尾随逗号。

new_game <- function(...) {
  list(...)
}

game <- new_game(
  c(1,2,3),
  c(1,2),
  c(3),
  c(2),
  c(1), # the comma here is the culprit
)

是否可以通过简单地忽略最后一个“参数”来规避这个错误?

我想这样设计我的函数,因为类似于 Rust 在匹配语句或结构中的 trailing commas,或者 Go 在复合文字中的 trailing commas,它使重新排列、添加、删除行和提交和拉取更改。

【问题讨论】:

    标签: r function ellipsis


    【解决方案1】:

    原来... 上有一个完整的documentation,可以使用...length()...elt(x) 访问特定参数。我决定将所有内容放在一个 try-catch 块中 - 如果抛出错误,可能是由于最后缺少参数(注意 missing(...elt(...length())) 不起作用)。

    game <- function(...) {
      tryCatch(
        list(...),
        error = function(e) lapply(1:(...length()-1), function(x) ...elt(x))
      )
    }
    

    或者rlang 专门为此用例提供list2

    game <- function(...) {
      rlang::list2(...)
    }
    

    【讨论】:

    • 不幸的是,tryCatch 解决方案掩盖了其他错误,所以我会(强烈)建议不要这样做。您可以手动执行此操作(无需rlang::list2),但它涉及迭代未评估的函数参数(例如通过function (...) match.call(expand.dots = FALSE)$...),并手动评估它们。
    • 在error函数中调用lapply时不应该还是会报错吗? (当然在这种情况下忽略最后一个参数仍然可能不理想)
    • 对,如果错误在最后一个参数中(例如game(1, stop('foo'))),则失败。如果错误出现在其他地方,它确实会停止,但它也会创建额外的(并且让用户感到困惑)错误消息 (game(1, stop('foo'), 2))。当然,这当然不是世界末日。
    【解决方案2】:

    R 是一个奇怪的野兽,因为即使语法清楚地允许尾随逗号,它也不像其他语言那样丢弃/忽略它们。相反,R 假装一个“缺失”的参数已经通过。只要没有任何东西触及缺失的论点,那没关系。我们甚至可以在没有点的情况下使用这种情况:

    f = function (a, b, c) a + b
    

    由于c 从未被读取,我们不需要传递它:

    f(1, 2)   # works
    f(1, 2, ) # works, too
    

    也许不是很有用。但以下也有效:

    g = function (a, b, c) a + b + if (missing(c)) 0 else c
    
    g(1, 2)    # 3
    g(1, 2, )  # 3
    g(1, 2, 3) # 6
    

    ...不幸的是,这并不能帮助我们直接捕获...

    没有使用已编写好的解决方案(例如rlang::list2),捕获点(允许尾随逗号)的唯一真正方法是处理未评估参数,并手动评估它们(相反,我们可能会想尝试missing(...elt(...length()));唉 R 不接受)。

    获取未评估的点参数有不同的方法。最简单的方法是使用match.call(expand.dots = FALSE)$...。这给我们留下了:

    new_game = function (...) {
        args = match.call(expand.dots = FALSE)$...
        nargs = length(args)
        if (identical(args[[nargs]], quote(expr = ))) nargs = nargs - 1L
        lapply(args[seq_len(nargs)], eval, envir = parent.frame())
    }
    

    【讨论】:

      猜你喜欢
      • 2019-02-01
      • 2021-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多