Frage

Beim Experimentieren mit den neuen Referenzklassen in RI bemerkte ein seltsames Verhalten, wenn Sie die Notation [[]] für Methoden verwenden (x [["Dosen etwas"] anstelle von x $ doomething). Diese Notation funktioniert für Fields, aber ich dachte zunächst, sie würde nicht für Methoden funktionieren, bis ich feststellte, dass Sie, wenn Sie "Klasse (x $ dosomething) ausführen", dann [[]] danach verwenden können. Das folgende einfache Beispiel zeigt den Punkt.

setRefClass("Number", 
  fields = list(
    value = "numeric"
  ),
  methods = list(
    addOne = function() {
      value <<- value + 1
    }
  )
)

X <- new("Number", value = 1)

X[['value']]         # 1

X[["addOne"]]()      # Error: attempt to apply non-function
class(X[["addOne"]]) # NULL

class(X$addOne)      # "refMethodDef"

# Now the following works!
X[["addOne"]]()      # sets X$value = 2
class(X[["addOne"]]) # "refMethodDef"

Der Grund, warum ich dies begegnet bin, ist, dass ich meine Objekte in einer Liste zusammenarbeiten und eine "applyMethod" -Funktion erstellen möchte, die eine angegebene Methode für jedes der Objekte innerhalb anwendet. Daher muss ich die Methode als Zeichenfolge angeben. Hat jemand irgendwelche Ideen, wie ich das erreichen kann?

War es hilfreich?

Lösung

Hier ist eine Klasse

.A <-
    setRefClass("A",
                fields=list(x="numeric"),
                methods=list(foo=function() x))

Wenn ich eine Instanz hätte a und wollte einen Anruf bei der "Foo" -Methode mit '$' erstellen, die ich konnte

eval(substitute(a$FUN(), list(FUN="foo")))

Also werde ich eine Klasse erstellen Alist Das soll eine Liste von Klassenelementen haben A (Dies könnte programmatisch erzwungen werden) und das hat a .delegate Methode, die eine willkürliche Methode auf alle Elemente der Liste anwendet. Ich werde dann eine Methode hinzufügen, die delegiert foo.

.delegate <- function(FUN, ...)
{
    lapply(elts, function(elt, ...) {
        eval(substitute(elt$FUN(...), list(FUN=FUN, ...)))
    })
}

.Alist <-
    setRefClass("Alist",
                fields=list(elts="list"),
                methods=list(
                  initialize = function(...) callSuper(elts=list(...)),
                  .delegate = .delegate,
                  foo=function() .delegate("foo")))

Und dann benutze es

> aList <- .Alist$new(.A$new(x=1), .A$new(x=2))
> aList$foo()
[[1]]
[1] 1

[[2]]
[1] 2

Andere Tipps

Grundsätzlich kann die R5 -Ref -Klasse die Methode erst zwischengespeichert, wenn dies erforderlich ist. Dies ist wahrscheinlich eine Art verzögerte Bewertung.

Und das Caching findet statt, wenn Sie über die Methode zugreifen $. Afaik, es gibt keine Möglichkeit, über [[String]] auf die Methode zuzugreifen

Sie können jedoch eine Problemumgehung mit .dollarforenvrefClass wie folgt finden:

> X <- new("Number", value = 1)
> ls(X@.xData)
[1] "value" # no methods named "addOne" before caching
> X[["addOne"]]
NULL
> methods:::.dollarForEnvRefClass(X, "addOne") # cache it
Class method definition for method addOne()
function () 
{
    value <<- value + 1
}
<environment: 0x116a4aa00>
> ls(X@.xData)
[1] "addOne" "value"  # you can find it
> X$value # value is 1
[1] 1
> X[["addOne"]]() # call the method
> X$value  # the method works
[1] 2

Wenn Sie an mehr Details interessiert sind, finden Sie in der Implementierung:
http://svn.r-project.org/r/trunk/src/library/methods/r/refclass.r

Vielleicht gibt es einen einfacheren Weg.

Melden Sie als Fehler auf R-DEVEL, damit John Chambers es beheben kann.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top