Wie man Zwangsmethoden schreibt
-
27-10-2019 - |
Frage
Ich habe ein paar maßgefertigte Referenzkurse und möchte für einige von ihnen Zwangsmethoden schreiben. Es wäre schön, wenn ein Funktionsaufruf so aussehen würde:
objectCoerce(src=obj, to="list", ...)
wo ...
ist der entscheidende Teil, da ich manchmal zusätzliche Dinge für bestimmte Zwang bestehen möchte (siehe do.deep = TRUE/FALSE
unter.
Um dies zu tun, muss ich jedoch einen "Transformator" implementieren, der das nimmt to
Argument versucht, ein leeres Objekt der Klasse zu instanziieren to
Und ruft dann den "regulären" Methodenversand auf? Oder gibt es einen besseren Weg?
Unten finden Sie meine aktuelle Lösung. Es funktioniert, aber ich "verliere" die Option, zum Unterricht zu zwingen character"
Da diese Klasse verwendet wird, um Dinge an den regulären Dispatcher und a zu verarbeiten to = "character
würde zu unendlicher Rekursion führen. Außerdem ist es viel Overhead.
Bearbeiten 2011-12-02
Na sicher setAs
wäre die erste Adresse, die es überprüfen würde. Aber die von arg angegebene Funktion def
in setAs
Kann nur ein Argument nehmen, und das ist oft zu starr für mich. Zum Beispiel sehe ich nicht, wie ich das einschließen kann do.deep = TRUE/FALSE
Wechseln Sie bei Verwendung setAs
.
Klasse defs
setRefClass(Class="MyVirtual")
setRefClass(
Class="A",
contains="MyVirtual",
fields=list(
x="character"
)
)
setRefClass(
Class="B",
contains="MyVirtual",
fields=list(
x.a="A",
x.b="numeric",
x.c="data.frame"
)
)
setGeneric(
name="objectCoerce",
signature=c("src", "to"),
def=function(src, to, ...){
standardGeneric("objectCoerce")
}
)
Generische Methode
setGeneric(
name="objectCoerce",
signature=c("src", "to"),
def=function(src, to, ...){
standardGeneric("objectCoerce")
}
)
Zwischentransformator
setMethod(
f="objectCoerce",
signature=signature(src="ANY", to="character"),
definition=function(src, to, do.deep=FALSE, ...){
# Transform 'to' to a dummy object of class 'to'
to.0 <- to
# For standard R classes
try.res <- try(eval(substitute(
to <- CLASS(),
list(CLASS=as.name(to.0))
)), silent=TRUE)
# For S4 classes
if(inherits(try.res, "try-error")){
try.res <- try(eval(substitute(
to <- new(CLASS),
list(CLASS=to.0)
)), silent=TRUE)
# For my classes. In order to get an 'hollow' object, some of them
# need to be instantiated by 'do.hollow=TRUE'
if(inherits(try.res, "try-error")){
try.res <- try(eval(substitute(
to <- new(CLASS, do.hollow=TRUE),
list(CLASS=to.0)
)), silent=TRUE)
if(inherits(try.res, "try-error")){
stop(try.res)
}
}
}
# Pass transformed 'to' along so the standard method
# dispatcher can kick in.
out <- objectCoerce(src=src, to=to, do.deep=do.deep, ...)
return(out)
}
)
Zwangsmethode 'myvirtual' zu 'List'
setMethod(
f="objectCoerce",
signature=signature(src="MyVirtual", to="list"),
definition=function(src, to, do.deep=FALSE, ...){
fields <- names(getRefClass(class(src))$fields())
out <- lapply(fields, function(x.field){
src$field(x.field)
})
names(out) <- fields
if(do.deep){
out <- lapply(out, function(x){
out <- x
if(inherits(x, "MyVirtual")){
out <- objectCoerce(src=x, to=to, do.deep=do.deep, .ARGS=.ARGS)
}
return(out)
})
}
return(out)
}
)
Testlauf
x <- new("B", x.a=new("A", x="hello world!"), x.b=1:5,
x.c=data.frame(a=c(TRUE, TRUE, FALSE)))
> objectCoerce(src=x, to="list")
$x.a
Reference class object of class "A"
Field "x":
[1] "hello world!"
$x.b
[1] 1 2 3 4 5
$x.c
a
1 TRUE
2 TRUE
3 FALSE
> objectCoerce(src=x, to="list", do.deep=TRUE)
$x.a
$x.a$x
[1] "hello world!"
$x.b
[1] 1 2 3 4 5
$x.c
a
1 TRUE
2 TRUE
3 FALSE
Lösung
Verwenden Sie möglicherweise SETAS, um eine Koerce -Methode zu erstellen (obwohl man lieber die eigene Basisklasse zum Schreiben der Methode hätte, anstatt dies für EnvrefClass zu tun)
setAs("envRefClass", "list", function(from) {
fields <- names(getRefClass(class(from))$fields())
Map(from$field, fields)
})
und dann
> as(new("B"), "list")
$x.a
Reference class object of class "A"
Field "x":
character(0)
$x.b
numeric(0)
$x.c
data frame with 0 columns and 0 rows
? Die tiefe Version könnte wie sein
setAs("envRefClass", "list", function(from) {
fields <- names(getRefClass(class(from))$fields())
curr <- Map(from$field, fields)
recurr <- sapply(curr, is, "envRefClass")
curr[recurr] <- lapply(curr[recurr], as, "list")
curr
})
Ich habe keine guten Ideen, um diese zu kombinieren, außer dass ich eine PSUDO-Klasse 'Deep_List' und eine Koerce-Methode dafür erstellen kann. Ich habe das Gefühl, dass ich Ihren Beitrag nicht verstehe.