Использование нотации [[]] для методов ссылочного класса - PullRequest
7 голосов
/ 30 апреля 2011

Экспериментируя с новыми ссылочными классами в RI, вы заметили странное поведение, если вы используете нотацию [[]] для методов (X [["doSomething"]] вместо X $ doSomething).Эта нотация работает для полей, но сначала я думал, что она не будет работать для методов, пока не обнаружил, что если вы выполните "class (X $ doSomething)", вы сможете потом использовать "[[]]".Простой пример, приведенный ниже, иллюстрирует эту точку.

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"

Причина, с которой я столкнулся, заключается в том, что я хочу сгруппировать свои объекты вместе в списке и создать функцию applyMethod, которая применяет определенный метод к каждомуобъекты внутри.Поэтому мне нужно указать метод в виде строки.У кого-нибудь есть идеи, как мне этого добиться?

Ответы [ 3 ]

4 голосов
/ 30 апреля 2011

Вот класс

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

Если бы у меня был экземпляр a и я хотел бы создать вызов метода 'foo', используя '$', я мог бы

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

Поэтому я создам класс Alist, который должен иметь список элементов класса A (это может быть реализовано программно), и который имеет метод .delegate, который будет применять произвольный метод ко всем элементам.из списка.Затем я добавлю метод, который делегирует 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")))

, а затем использую его

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

[[2]]
[1] 2
2 голосов
/ 30 апреля 2011

в основном R5 ref класс не кэширует метод, пока он не понадобится. Вероятно, это своего рода задержанная оценка.

И кэширование происходит при доступе к методу через $. Так что, AFAIK, нет способа получить доступ к методу через [[string]]

Но вы можете найти обходной путь, используя .dollarForEnvRefClass, например так:

> 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

если вас интересует более подробная информация, см. Реализацию:
http://svn.r -project.org / R / багажник / SRC / библиотека / методы / R / refClass.R

Может быть, есть более простой способ.

0 голосов
/ 30 апреля 2011

Сообщить об ошибке на r-devel, чтобы Джон Чамберс смог ее исправить.

...