2

我想继承一个 S4 类并向该子类添加一个特殊方法。该方法应该只适用于子类,它对我的​​应用程序中的任何其他类都没有意义。

    setClass("MySpecies", contains="Species", ##Species is an S4 class
         representation(x="numeric"))

setMethod("initialize", "MySpecies", function(.Object, x, ...){
  .Object@x <- x
  args <- list(...)
  for(i in seq_len(length(args))){
    attr(.Object, names(args)[i]) <- args[[i]]
  }
  .Object
})

##CalcMatrix <- function(.Object, y){
##  x <- .Object@x
##  matrix(x, x*2, y*3)
##}

setGeneric("CalcMatrix", function(object, y){standardGeneric("CalcMatrix")})
setMethod("CalcMatrix", "MySpecies",function(object, y){
  x <- object@x
  matrix(x, x*2, y*3)
})

随着setGeneric它的工作,但我真的必须定义一个通用函数,尽管它只会与这个对象一起使用吗?注释掉的部分有效,但是没有检查是否使用正确的参数调用函数。这样做的正确方法是什么?提前致谢。

4

1 回答 1

3

您想要使用方法分派,并且每个方法都需要与泛型相关联,所以是的,setGeneric是必需的。

还有一点不请自来的建议......使用正式的类系统(大概是因为定义明确的类有助于编写更复杂的程序)然后通过添加任意属性来颠覆结构有点奇怪;这些确实应该是您班级中额外的、定义明确的插槽。

让我们通过定义使您的示例可重现Species

setClass("Species", representation(y="numeric"))
setClass("MySpecies", contains="Species", ##Species is an S4 class
         representation(x="numeric"))

S4 类的一个隐含要求是new("MySpecies")有效的;您的initialize方法未通过此测试(因为x没有默认值)。此外,通常的做法是期望初始化MySpecies调用initialize它包含的类的方法。可以写

setMethod("initialize", "MySpecies", function(.Object, ..., x=numeric()) {
    callNextMethod(.Object, x=x, ...)
})

请注意callNextMethod,以便正确初始化基类。使用...并将其传递给callNextMethod意味着可能在其中定义的插槽Species也将被正确初始化。此外,x需要在之后...,因为initialize被定义为采用代表包含类的未命名参数——new("MySpecies", new("Species"))即使它是一种构造参数的方式,您不直接使用也是如此。上面的initialize方法实际上除了默认的初始化方法之外没有做任何事情,所以实际上(通常是这种情况)根本不编写初始化方法是有意义的。

然后在最近的 R 中,setClass返回一个默认构造函数,所以

MySpecies <- setClass("MySpecies", contains="Species", ##Species is an S4 class
                      representation(x="numeric"))

进而

> MySpecies(x=1:5, y=5:1)
An object of class "MySpecies"
Slot "x":
[1] 1 2 3 4 5

Slot "y":
[1] 5 4 3 2 1
于 2013-01-19T23:55:03.530 回答