【问题标题】:Using sd as a generic function in R在 R 中使用 sd 作为通用函数
【发布时间】:2025-12-01 06:30:01
【问题描述】:

如果我有一个名为 foo 的类,那么重载 summary 函数很简单

summary.foo = function(x, ...) print("bar")

但是这种技术不适用于sd 函数,即

> bar = createFooClass()
> sd.foo = function(x, ...) print("Hi")
> sd(bar)
  error: is.atomic(x) is not TRUE

重载这个函数的正确方法是什么?

【问题讨论】:

    标签: oop r r-s3


    【解决方案1】:

    您可以劫持任何非泛型函数,使其 (S3) 泛型并将原始版本设置为默认版本。例如:

    ## make an S3 generic for sd
    sd <- function(x, ...) UseMethod("sd")
    ## take the usual definition of sd,
    ## and set it to be the default method
    sd.default <- stats::sd
    ## create a method for our class "foo"
    sd.foo = function(x, ...) print("Hi")
    

    如果这是在包中,最后一步是向sd.default 添加一个... 参数以允许通过包检查:

    formals(sd.default) <- c(formals(sd.default), alist(... = ))
    

    给予:

    > args(sd.default)
    function (x, na.rm = FALSE, ...) 
    NULL
    > args(stats::sd)
    function (x, na.rm = FALSE) 
    NULL
    

    然后给出所需的行为:

    > bar <- 1:10
    > sd(bar)
    [1] 3.027650
    > class(bar) <- "foo"
    > sd(bar)
    [1] "Hi"
    

    这在编写 R 扩展手册的 section 7.1 中有记录

    【讨论】:

    • 最好向 R-devel 发送电子邮件并请求将sd(或更好,var)设为通用。
    • @hadley 表示同意,但除了需要 R Core 来维护这一点外,在制作通用内容时也会对性能造成影响,因此 R Ext. 中的措辞和建议。手动。
    • 我不相信这些借口。为什么应该是泛型而不是 var?
    • @hadley 他们不是我的借口;-)(我同意你的观点)无论如何,在你使用它之前你会有点等待 R Core 实现它 - 所以“劫持”方法仍然很有价值,直到 R Core 确实发布了以sd() 作为泛型的 R 的稳定版本。
    • 抱歉,我的评论应该更清楚 - 有时您需要让 R-core 经历一段艰难的时间,然后他们才会实施明确需要的更改。
    【解决方案2】:

    您需要为sd 定义一个新的泛型。

    最简单的方法是使用 S4,因为它会自动处理默认的“sd”方法:

    setClass("foo", list(a = "numeric", names = "character"))
    
    setGeneric("sd")
    
    setMethod("sd", "foo", 
              function(x,  na.rm = FALSE){
                  print("This is a foo object!")
                  callNextMethod(x@a)
                  })
    
    tf <- new("foo", a = 1:10)
    sd(tf)
    #[1] "This is a foo object!"
    #[1] 3.027650
    

    【讨论】:

      【解决方案3】:

      查看sd()的代码---它有效地在内部调度。换句话说,它不是一个泛型函数,而是一个普通的旧正则函数。

      最简单的可能就是修改sd() 以在类foo 上分支。

      【讨论】:

      • 有趣的是,这就是我所做的,但它似乎“错误”并且有点尴尬。