2011-04-30 19 views
7

Al experimentar con las nuevas clases de referencia en RI noté un comportamiento extraño si usa la notación" [[]] "para los métodos (X [[" doSomething "]] en lugar de X $ doSomething). Esta notación funciona para los campos, pero inicialmente pensé que no funcionaría para los métodos hasta que descubrí que si ejecuta "clase (X $ doSomething)", puede usar "[[]]" después. El ejemplo simple a continuación ilustra el punto.Usando la notación "[[]] para métodos de clase de referencia

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 razón me encontré con esto es porque quiero mi grupo de objetos juntos en una lista y crear una función "applyMethod" que se aplica un método especificado en cada uno de los objetos dentro. Por lo tanto, necesito especificar el método como una cadena. ¿Alguien tiene alguna idea de cómo puedo lograr esto?

+0

se supone clases referencia a una instancia como '.A = setRefClass (<...>); .A $ nuevo() '. ¿'[[' Está destinado a ser utilizado para el acceso de miembros? De '? ReferenceClasses' la API es' $ '. También podría colorear dentro de las líneas. –

Respuesta

4

Aquí es una clase

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

Si tuviera una instancia a y quería construir una llamada al método 'foo' usando '$' Podría

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

Así que voy a crear una clase Alist que debe tener una lista de elementos de la clase A (esto se puede aplicar mediante programación), y que tiene un método .delegate que aplicará un método arbitrario a todos los elementos de la lista. A continuación, agregaré un método que 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"))) 

y luego usarlo

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

[[2]] 
[1] 2 
2

básicamente la clase de referencia R5 no almacena en caché el método hasta que es necesario. Esta es probablemente una especie de evaluación retrasada.

Y el almacenamiento en caché tiene lugar cuando accede al método a través del $. Así, que yo sepa, no hay manera de acceder al método a través de [[cadena]]

Pero se puede encontrar una solución utilizando .dollarForEnvRefClass así:

> X <- new("Number", value = 1) 
> ls([email protected]) 
[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([email protected]) 
[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 usted está interesado en más detalle, vea la implementación:
http://svn.r-project.org/R/trunk/src/library/methods/R/refClass.R

Quizás haya una manera más directa.

+0

Creo que el término "R5" no es la forma correcta de referirse a las clases de referencia. Vea los comentarios aquí http://stackoverflow.com/questions/5137199/what-is-the-significance-of-the-new-reference-classes –

0

Informe como error en r-devel para que John Chambers pueda arreglarlo.

Cuestiones relacionadas