L'utilisation de « [[]] » notation pour les méthodes de classe de référence

StackOverflow https://stackoverflow.com/questions/5841339

  •  27-10-2019
  •  | 
  •  

Question

En expérimentant les nouvelles classes de référence en R j'ai remarqué un comportement étrange si vous utilisez le "[[]]" notation des méthodes (X [[ "DoSomething"]] au lieu de X $ DoSomething). Cette notation fonctionne pour les champs, mais je d'abord pensé qu'il ne travaillerait pour les méthodes jusqu'à ce que je trouve que si vous exécutez « classe (X $ doSomething) » vous pouvez alors utiliser « [[]] » par la suite. L'exemple simple ci-dessous illustre le point.

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"

La raison pour laquelle je rencontrais c'est parce que je veux regrouper mes objets ensemble dans une liste et de créer une fonction « applyMethod » qui applique une méthode déterminée sur chacun des objets à l'intérieur. Par conséquent, je dois spécifier la méthode comme une chaîne. Est-ce que quelqu'un a des idées comment je peux y parvenir?

Était-ce utile?

La solution

Voici une classe

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

Si j'avais une a instance et je voulais construire un appel à la méthode « foo » avec « $ » je pouvais

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

Je vais créer une Alist de classe qui est censé avoir une liste d'éléments de A de classe (ce qui pourrait être programme appliquée), et qui a une méthode .delegate qui va appliquer une méthode arbitraire à tous les éléments de la liste . Je vais ensuite ajouter une méthode que les délégués 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")))

Et puis utilisez

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

[[2]]
[1] 2

Autres conseils

essentiellement la classe R5 ne cache pas la méthode jusqu'à ce qu'il soit nécessaire. Ceci est probablement une sorte d'évaluation retardée.

Et la mise en cache a lieu lorsque vous accédez à la méthode par $. Donc, autant que je sache, il n'y a pas moyen d'accéder à la méthode par [[chaîne]]

Mais vous pouvez trouver une solution à l'aide .dollarForEnvRefClass comme ceci:

> 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

si vous êtes intéressé par plus de détails, voir la mise en œuvre:
http://svn.r-project.org /R/trunk/src/library/methods/R/refClass.R

Peut-être qu'il est beaucoup plus simple.

Signaler comme bug sur r-devel si John Chambers peut le fixer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top