【问题标题】:How do I dispatch cat in R S3?如何在 R S3 中调度 cat?
【发布时间】:2014-02-19 19:48:28
【问题描述】:
> foo <- structure(list(one=1,two=2), class = "foo")

> cat(foo)
Error in cat(list(...), file, sep, fill, labels, append) : 
  argument 1 (type 'list') cannot be handled by 'cat'

好的,我将它添加到通用猫中:

> cat.foo<-function(x){cat(foo$one,foo$two)}
> cat(foo)
Error in cat(list(...), file, sep, fill, labels, append) : 
  argument 1 (type 'list') cannot be handled by 'cat'

没有骰子。

【问题讨论】:

  • 如果函数一开始就不是通用的,那么仅仅编写一个名为 function.class 的新函数并没有多大作用。话虽如此,我还没有尝试过,但我感觉 cat 有 ... 作为它的第一个参数可能会导致一些并发症
  • 直接调用 cat.foo 有什么明显的错误吗? cat.foo(foo)
  • 一个快捷的解决方案是定义print.foo
  • &gt; print.foo&lt;-function(x){cat(foo$one,foo$two)} &gt; cat(foo) Error in cat(list(...), file, sep, fill, labels, append) : argument 1 (type 'list') cannot be handled by 'cat'
  • 我认为 agstudy 暗示您使用 print 而不是 cat。为什么您需要为此使用 cat ? print 已经是通用的,因此为自己的类编写自己的方法很容易。

标签: r r-s3


【解决方案1】:

你不能。 cat() 不是泛型函数,因此您不能为其编写方法。

您可以制作通用的cat() 的新版本:

cat <- function(..., file = "", sep = " ", fill = FALSE, labels = NULL,
                append = FALSE) {
  UseMethod("cat")
}
cat.default <- function(..., file = "", sep = " ", fill = FALSE, labels = NULL,
                append = FALSE) {
  base::cat(..., file = file, sep = sep, fill = fill, labels = labels, 
    append = append)
}

但是在... 上调度的语义没有很好的定义(我找不到它的记录在哪里,如果在任何地方的话)。看起来调度仅基于... 中的第一个元素:

cat.integer <- function(...) "int"
cat.character <- function(...) "chr"
cat(1L)
#> [1] "int"
cat("a")
#> [1] "chr"

这意味着忽略第二个和所有后续参数的类:

cat(1L, "a")
#> [1] "int"
cat("a", 1L)
#> [1] "chr"

如果你想在cat() 中添加一个foo 方法,你只需要做一些额外的检查:

cat.foo <- function(..., file = "", sep = " ", fill = FALSE, labels = NULL,
                    append = FALSE) {
  dots <- list(...)
  if (length(dots) > 1) {
    stop("Can only cat one foo at a time")
  }
  foo <- dots[[1]]
  cat(foo$one, foo$two, file = file, sep = sep, fill = fill, labels = labels, 
    append = append)
  cat("\n")
}
foo <- structure(list(one=1,two=2), class = "foo")
cat(foo)
#> 1 2

【讨论】:

  • 我不认为你在这里提出了令人信服的论点。您是想说没有人可以制作自己的通用功能吗? (我知道这不是您要提出的论点 - 但不清楚为什么您不能将 cat 定义为泛型并让 cat.default 调用 base::cat)。我想我实际上让它工作了,但它是一个杂项,我不喜欢它,所以我暂时不会发布我的解决方法作为解决方案 - 但我想听听你对此有什么看法。
  • @Dason 向base::cat 添加方法很重要,因为它不是通用的。您当然可以编写自己的通用函数并将其命名为 cat(),但 ... 调度的语义很棘手,正如我在更新的答案中所描述的那样。
  • 现在这是一个更好的答案。谢谢!
【解决方案2】:

如果您帖子中的示例是您真正想要实现的目标,而不仅仅是一些解释您的观点的玩具示例,您可以简单地重新定义 cat 以以所需的方式处理 lists:

cat <- function(...) do.call(base::cat, as.list(do.call(c, list(...))))

R> cat(list(1,2))
1 2R> cat(list(1,2), sep=',')
1,2R> cat(c(1,2))
1 2R> cat(c(1,2), sep=',')
1,2R> 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    • 2021-11-19
    • 2021-06-06
    • 2018-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多