Pergunta

Enquanto experimentava com as novas classes de referência em R, notei alguns comportamentos estranhos se você usar a notação "[[]]" para métodos (X [["doSomething"]] em vez de X $ doSomething).Essa notação funciona para campos, mas inicialmente pensei que não funcionaria para métodos até que descobri que se você executar "class (X $ doSomething)", poderá usar "[[]]" posteriormente.O exemplo simples abaixo ilustra o ponto.

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"

O motivo pelo qual encontrei isso é porque desejo agrupar meus objetos em uma lista e criar uma função "applyMethod" que aplica um método especificado em cada um dos objetos.Portanto, preciso especificar o método como uma string.Alguém tem alguma ideia de como posso conseguir isso?

Foi útil?

Solução

Aqui está uma aula

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

Se eu tivesse uma instância a e quisesse construir uma chamada para o método 'foo' usando '$', eu poderia

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

Então, vou criar uma classe Alist que se destina a ter uma lista de elementos da classe A (isso pode ser aplicado programaticamente) e que tem um método .delegate que aplicará um método arbitrário a todos os elementos da lista.Em seguida, adicionarei um 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")))

E então use-o

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

[[2]]
[1] 2

Outras dicas

basicamente a classe R5 ref não armazena o método em cache até que seja necessário.Este é provavelmente um tipo de avaliação atrasada.

E o armazenamento em cache ocorre quando você acessa o método via $. Então, AFAIK, não há como acessar o método via [[string]]

Mas você pode encontrar uma solução 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

se você estiver interessado em mais detalhes, consulte a implementação:
http://svn.r-project.org/R/trunk/src/library/methods/R/refClass.R

Talvez haja uma maneira mais direta.

Reporte como bug no r-devel para que John Chambers possa corrigi-lo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top