问题来自试验包并发现使用new(Class = 'ddmatrix', Data = X)
和ddmatrix(Data = X)
产生不同的结果,其中X
是一个矩阵(可以认为类ddmatrix
是转换的班级matrix
)。
在包中,定义了S4类ddmatrix
。 setGeneric(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',...)
,这是默认的吗?
答案 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#L191的new()
构造对象。另一个包作者可能采用了不同的设计,其中有几种方法分别调用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))
来创建相同的对象?我们可以,但是当作者决定改变他们的实现以便存储每行开头的偏移时,我们必须理解作者所做的事情并更新我们的代码。