如何定义S4 引用类实例的字段默认值?
对于常规 S4 课程,有以下prototype
论点:
setClass("Test_1",
representation(
x.1="numeric",
x.2="logical",
x.3="matrix"
),
prototype=list(
x.1=10,
x.2=FALSE,
x.3=matrix(0,0,0)
)
)
> new("Test_1")
An object of class "Test_1"
Slot "x.1":
[1] 10
Slot "x.2":
[1] FALSE
Slot "x.3":
<0 x 0 matrix>
据我了解的帮助页面,这也应该适用于通过参数setRefClass
的 S4 参考类。...
相应的部分说:
...要传递给 setClass 的其他参数。
然而prototype
似乎没有setClass
正确发送到:
gen <- setRefClass("Test_2",
fields=list(
x.1="numeric",
x.2="logical",
x.3="matrix"
),
prototype=list(
x.1=10,
x.2=FALSE,
x.3=matrix(0,0,0)
)
)
> gen$new()
Reference class object of class "Test_2"
Field "x.1":
numeric(0)
Field "x.2":
logical(0)
Field "x.3":
<0 x 0 matrix>
或者
> new("Test_2")
Reference class object of class "Test_2"
Field "x.1":
numeric(0)
Field "x.2":
logical(0)
Field "x.3":
<0 x 0 matrix>
我没有在setRefClass
.
这是一个错误还是我在这里遗漏了一些明显的东西?
编辑
我能找到的最接近的可以帮助我声明默认值的是$initFields()
.
这就是?setRefClass
不得不说的:
从提供的参数初始化对象的字段。此方法通常仅从具有 $initialize() 方法的类调用。它对应于引用类的默认初始化。如果有插槽和非引用超类,这些也可以在 ... 参数中提供。
通常,一个专门的 $initialize() 方法执行它自己的计算,然后调用 $initFields() 来执行标准初始化,如下面示例中的 matrixViewer 类所示。
到现在为止还挺好
gen <- setRefClass("Test_3",
fields=list(
x.1="numeric",
x.2="logical",
x.3="matrix"
),
methods=list(
initialize=function(
...
) {
.self$initFields(x.1=10, x.2=TRUE, x.3=matrix(0,0,0), ...)
}
)
)
适用于“默认初始化案例”:
> gen$new()
Reference class object of class "Test_3"
Field "x.1":
[1] 10
Field "x.2":
[1] TRUE
Field "x.3":
<0 x 0 matrix>
但是,如果无法处理在初始化时明确指定(某些)字段值的情况:
> gen$new(x.1=100)
Reference class object of class "Test_3"
Field "x.1":
[1] 10
Field "x.2":
[1] TRUE
Field "x.3":
<0 x 0 matrix>
解决方法
真的很脏,但它的工作原理
gen <- setRefClass("Test_4",
fields=list(
x.1="numeric",
x.2="logical",
x.3="matrix"
),
methods=list(
initialize=function(
...
) {
defaults <- list(
x.1=10,
x.2=FALSE,
x.3=matrix(0,0,0)
)
if (!missing(...)) {
x.args <- list(...)
specified <- names(x.args)
idx <- which(specified %in% names(defaults))
if (length(idx)) {
for (ii in specified[idx]) {
defaults[[ii]] <- x.args[[ii]]
}
}
}
.self$initFields(x.1=defaults$x.1, x.2=defaults$x.2,
x.3=defaults$x.3, ...)
}
)
)
初始化
> gen$new()
Reference class object of class "Test_4"
Field "x.1":
[1] 10
Field "x.2":
[1] FALSE
Field "x.3":
<0 x 0 matrix>
> gen$new(x.1=100)
Reference class object of class "Test_4"
Field "x.1":
[1] 100
Field "x.2":
[1] FALSE
Field "x.3":
<0 x 0 matrix>
> gen$new(x.1=100)
这就是我正在寻找的东西,但我确定还有更多“内置”的东西?
编辑 2
整个事情有点通用。方法ensureDefaultValues
可以是每个其他类继承自的类的方法。对于“继承路径更远”的类,可以简单地在方法内调用此intialize
方法:
gen <- setRefClass("RootClass",
methods=list(
ensureDefaultValues=function(values, ...) {
if (!missing(...)) {
arguments <- list(...)
specified <- names(arguments)
idx <- which(specified %in% names(values))
if (length(idx)) {
for (ii in specified[idx]) {
values[[ii]] <- arguments[[ii]]
}
}
}
temp <- paste(paste0(names(values), "=values$",
names(values)), collapse=", ")
eval(parse(text=paste0(".self$initFields(", temp, ", ...)")))
return(TRUE)
}
)
)
gen <- setRefClass("Test_5",
contains="RootClass",
fields=list(
x.1="numeric",
x.2="logical",
x.3="matrix"
),
methods=list(
initialize=function(
...
) {
.self$ensureDefaultValues(
values=list(
x.1=10,
x.2=FALSE,
x.3=matrix(0,0,0)
),
...
)
return(.self)
}
)
)
> gen$new()
Reference class object of class "Test_5"
Field "x.1":
[1] 10
Field "x.2":
[1] FALSE
Field "x.3":
<0 x 0 matrix>
> gen$new(x.1=100)
Reference class object of class "Test_5"
Field "x.1":
[1] 100
Field "x.2":
[1] FALSE
Field "x.3":
<0 x 0 matrix>