S4 Reference Classesインスタンスのフィールドのデフォルト値を定義するにはどうすればよいですか?
通常の 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>