Из камер (отлично) Расширение R (2016) :
Метод валидации будет вызываться автоматически из метода по умолчанию для initialize (). Рекомендуемая форма метода initialize заканчивается вызовом callNextMethod (), чтобы гарантировать, что слоты подкласса могут быть указаны при вызове генератора для класса. Если следовать этому соглашению, инициализация закончится вызовом метода по умолчанию, и метод валидности будет вызван после того, как вся инициализация произойдет.
Я думал, что понял, но поведение, которое я получаюпохоже, не следует этому соглашению.
setClass("A", slots = c(s1 = "numeric"))
setValidity("A", function(object) {
if (length(object@s1) > 5) {
return("s1 longer than 5")
}
TRUE
})
setMethod("initialize", "A", function(.Object, s1, ...) {
if (!missing(s1)) .Object@s1 <- s1 + 4
callNextMethod(.Object, ...)
})
A <- new("A", rep(1.0, 6))
A
# An object of class "A"
# Slot "s1":
# [1] 5 5 5 5 5 5
validObject(A)
# Error in validObject(A) : invalid class “A” object: s1 longer than 5
Я ожидал, что проверка достоверности будет выполнена путем добавления callNextMethod()
в конец метода инициализации. Добавление явного validObject(.Object)
до того, как callNextMethod()
сработает, но я явно чего-то здесь не понимаю.
Очевидно, я также могу делать все те же проверки в методе достоверности, но в идеале вся проверка достоверности будетпроисходят в пределах setValidity
, поэтому будущие правки сохраняются в одном месте.
Небольшое изменение функции initialize
дает желаемый результат - есть ли причина использовать один подход над другим? Чемберс, похоже, предпочитает использовать .Object@<-
, тогда как в другом месте я видел следующий метод (Gentlemman & Hadley).
setMethod("initialize", "A", function(.Object, s1, ...) {
if (!missing(s1)) s1 + 4
else s1 <- numeric()
callNextMethod(.Object, s1 = s1, ...)
})