Domanda

Durante la sperimentazione con le nuove classi di riferimento in R, ho notato un comportamento strano se usi la notazione "[[]]" per i metodi (X [["doSomething"]] invece di X $ doSomething).Questa notazione funziona per i campi, ma inizialmente pensavo che non avrebbe funzionato per i metodi finché non ho scoperto che se esegui "class (X $ doSomething)" puoi usare "[[]]" in seguito.Il semplice esempio riportato di seguito illustra il punto.

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"

Il motivo per cui ho riscontrato questo problema è perché desidero raggruppare i miei oggetti in un elenco e creare una funzione "applyMethod" che applica un metodo specificato su ciascuno degli oggetti all'interno.Pertanto, è necessario specificare il metodo come stringa.Qualcuno ha qualche idea su come raggiungere questo obiettivo?

È stato utile?

Soluzione

Ecco una lezione

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

Se avessi un'istanza a e volessi costruire una chiamata al metodo "foo" utilizzando "$", potrei

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

Quindi creerò una classe Alist che ha lo scopo di avere un elenco di elementi della classe A (questo potrebbe essere applicato a livello di programmazione), e che ha un metodo .delegate che applicherà un metodo arbitrario a tutti gli elementi della lista.Aggiungerò quindi un metodo che delega 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")))

E poi usalo

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

[[2]]
[1] 2

Altri suggerimenti

fondamentalmente la classe ref R5 non memorizza nella cache il metodo finché non è necessario.Questa è probabilmente una sorta di valutazione ritardata.

E la memorizzazione nella cache avviene quando accedi al metodo tramite $. Quindi, AFAIK, non è possibile accedere al metodo tramite [[string]]

Ma puoi trovare una soluzione alternativa usando .dollarForEnvRefClass in questo modo:

> 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

se sei interessato a maggiori dettagli, guarda l'implementazione:
http://svn.r-project.org/R/trunk/src/library/methods/R/refClass.R

Forse esiste un modo più semplice.

Segnala come bug su r-devel in modo che John Chambers possa risolverlo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top