如何查找类

时间:2016-07-28 23:22:39

标签: r class object s4

问题来自试验包并发现使用new(Class = 'ddmatrix', Data = X)ddmatrix(Data = X)产生不同的结果,其中X是一个矩阵(可以认为类ddmatrix是转换的班级matrix)。

文档

在包中,定义了S4类ddmatrixsetGeneric(name = 'ddmatrix')的通用构造函数。此外,pacakge定义setMethod('ddmatrix', signature = 'matrix', ...)如下:

 setMethod("ddmatrix", signature(data="matrix"), 
              function(data, nrow=1, ncol=1, byrow=FALSE, ...
                       bldim=.pbd_env$BLDIM, ICTXT=.pbd_env$ICTXT)
    {
    dim(data) <- NULL
    ret <- ddmatrix(data=data, nrow=nrow, ncol=ncol, byrow=byrow, bldim=bldim, ICTXT=ICTXT)    
    return( ret )
}
)

我很困惑如何在上述ddmatrix步骤中使用方法setMethod('ddmatrix', signature = 'matrix')。此ddmatrix方法是通用ddmatrix的默认方法吗?

同时,当调用new('ddmatrix', Data = X)时,它将调用哪个方法从ddmatrix对象构建一个新的matrix对象? new功能是:

function (Class, ...) 
{
    ClassDef <- getClass(Class, where = topenv(parent.frame()))
    value <- .Call(C_new_object, ClassDef)
    initialize(value, ...)
}

问题

要回答new('ddmatrix')ddmatrix()之间的差异,我认为一种方法是找到默认构造函数。同时,该软件包还定义了setMethod('ddmatrix', signature = 'vector',...),这是默认的吗?

1 个答案:

答案 0 :(得分:3)

在某种程度上,这取决于作者。许多人严格对包开发人员查看new()@slot()(对于插槽访问) - 这些直接向用户公开实现细节 - 并且更喜欢编写构造函数和将接口放在实现之上的访问器。这似乎是您正在考虑的包的情况,其中ddmatrix()是面向用户的构造函数。

作者似乎已经实现了一种外观模式,其中几种不同的方法在调用另一个函数/方法来进行实际的对象构造之前进行相对较小的数据转换。根据你显示的内容,似乎ddmatrix,matrix-method调用ddmatrix,vector-method(因为在ddmatrix内部,矩阵方法函数设置dim(data) <- NULL,将矩阵转换为向量,然后调用ddmatrix()现在调度到vector方法),这通过https://github.com/RBigData/pbdDMAT/blob/master/R/constructors.r#L191new()构造对象。另一个包作者可能采用了不同的设计,其中有几种方法分别调用new()

文档通常也有帮助,例如,?ddmatrix不会通过new()讨论直接对象构建。

这是一个更简单的例子。我创建了一个类“A”,其中包含一个包含数字向量的插槽

setClass("A", slots=c(x="numeric"))

这里我创建了一个构造函数,因为我希望用户看到类的接口,而不是它的实现

A = function(x=numeric())
    new("A", x=x)

到目前为止,A()new("A")会返回具有相同结构的对象,例如

> new("A")
An object of class "A"
Slot "x":
numeric(0)

> A()
An object of class "A"
Slot "x":
numeric(0)

也许作为“A”类的开发者,我想要一个未初始化的类'A'的对象将'NA'作为插槽x的值,所以我修改

A = function(x = NA_real_)
    new("A", x=x)

现在直接调用new()会在调用A()时返回另一个对象

> new("A")
An object of class "A"
Slot "x":
numeric(0)

> A()
An object of class "A"
Slot "x":
[1] NA

哪一个'正确'?好吧,两者都是正确的,但作为类的创建者,我打算让用户通过调用函数A()来创建类“A”的对象。

从实现中分离接口(使用A()构造对象)的典型原因(使用new()构造对象)是因为实现对用户来说并不明显。这似乎是ddmatrix()函数的情况 - 由于只有包作者需要知道的原因,将R矩阵存储为具有维度信息的向量是很方便的。我猜一个简单的等价物可能是

setClass("A", slots=c(data="numeric", nrow="integer", ncol="integer"))
A = function(m=matrix(0, 0, 0)) {
    stopifnot(is(m, "matrix"))
    new("A", data=as.vector(m), nrow=nrow(m), ncol=ncol(m))
}
例如

> A(matrix(1:10, 5))
An object of class "A"
Slot "data":
 [1]  1  2  3  4  5  6  7  8  9 10

Slot "nrow":
[1] 5

Slot "ncol":
[1] 2

作者为什么要这样做?作为用户对我们无关紧要。为什么我们不能通过调用m = matrix(1:10, 5); new("A", data=as.vector(m), nrow=nrow(m), ncol(m))来创建相同的对象?我们可以,但是当作者决定改变他们的实现以便存储每行开头的偏移时,我们必须理解作者所做的事情并更新我们的代码。