Pregunta

Mientras experimentar con las nuevas clases de referencia en RI notó algún 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 descubriera que si ejecuta la clase "(X $ Dosomething)" luego puede usar [[]] después. El ejemplo simple a continuación ilustra el 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"

La razón por la que encontré esto es porque quiero agrupar mis objetos en una lista y crear una función "ApplyMethod" que 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?

¿Fue útil?

Solución

Aquí hay 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 '$' que podría

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

Entonces crearé una clase Alist que está destinado a tener una lista de elementos de clase A (esto podría aplicarse programáticamente), y eso tiene un .delegate Método que aplicará un método arbitrario a todos los elementos de la lista. Luego agregaré un método que delegue 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 úsalo

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

[[2]]
[1] 2

Otros consejos

Básicamente, la clase R5 REF no almacena en caché el método hasta que sea necesario. Este es probablemente un tipo de evaluación retrasada.

Y el almacenamiento en caché tiene lugar cuando accede al método a través de $. Entonces, AFAIK, no hay forma de acceder al método a través de [[String]

Pero puede encontrar una solución alternativa usando .DollarForenVrefClass como esta:

> 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 está interesado en más detalles, consulte la implementación:
http://svn.r-project.org/r/trunk/src/library/methods/r/refclass.r

Tal vez hay una manera más directa.

Informe como error en R-Delvel para que John Chambers pueda solucionarlo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top